Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103592719
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类: C/C++

2008-04-15 19:00:07

    来源:ChinaITLab   

异常

由于调用了Java的方法,因此难免产生操作的异常信息。这些异常没有办法通过C++本身的异常处理机制来捕捉到,但JNI可以通过一些函数来获取Java中抛出的异常信息。之前我们在Demo类中定义了一个方法throwExcp,下面将访问该方法并捕捉其抛出来的异常信息,代码如下:

/**
  假设我们已经构造了
一个Demo的实例obj,其类定义为cls
  */
  jthrowable excp = 0;
/* 异常信息定义 */
  jmethodID mid=(*env)->
GetMethodID(env,cls,"throwExcp","()V");
  /*如果mid为0表示获取方法定义失败*/
  jstring msg = 
(*env)-> CallVoidMethod(env, obj, mid);
  /* 在调用该方法后会有一个
IllegalAccessException的异常抛出 */
  excp = (*env)->ExceptionOccurred(env);
  if(excp)
{
  (*env)->ExceptionClear(env);
  //通过访问excp来获取具体异常信息
  /*
  在Java中,
大部分的异常信息都是扩展类java.lang.Exception,
因此可以访问excp的toString
或者getMessage来获取异常信息的内容。
访问这两个方法同前面讲到的
如何访问类的方法是相同的。
  */
  }

线程和同步访问

有些时候需要使用多线程的方式来访问Java的方法。我们知道一个Java虚拟机是非常消耗系统的内存资源,差不多每个虚拟机需要内存大约在20MB左右。为了节省资源要求每个线程使用的是同一个虚拟机,这样在整个的JNI程序中只需要初始化一个虚拟机就可以了。所有人都是这样想的,但是一旦子线程访问主线程创建的虚拟机环境变量,系统就会出现错误对话框,然后整个程序终止。

其实这里面涉及到两个概念,它们分别是虚拟机(JavaVM *jvm)和虚拟机环境(JNIEnv *env)。真正消耗大量系统资源的是jvm而不是env,jvm是允许多个线程访问的,但是env只能被创建它本身的线程所访问,而且每个线程必须创建自己的虚拟机环境env。

这时候会有人提出疑问,主线程在初始化虚拟机的时候就创建了虚拟机环境env。为了让子线程能够创建自己的env,JNI提供了两个函数:AttachCurrentThread和DetachCurrentThread。下面代码就是子线程访问Java方法的框架:

DWORD WINAPI ThreadProc(PVOID dwParam)
  {
  JavaVM jvm = (JavaVM*)dwParam;
/* 将虚拟机通过参数传入 */
  JNIEnv* env;
  (*jvm)-> AttachCurrentThread
(jvm, (void**)&env, NULL);
  .........
(*jvm)-> DetachCurrentThread(jvm);
  }

时间

关于时间的话题是我在实际开发中遇到的一个问题。当要发布使用了JNI的程序时,并不一定要求客户要安装一个Java运行环境,因为可以在安装程序中打包这个运行环境。为了让打包程序利于下载,这个包要比较小,因此要去除JRE(Java运行环境)中一些不必要的文件。

但是如果程序中用到Java中的日历类型,例如java.util.Calendar等,那么有个文件一定不能去掉,这个文件就是[JRE]\lib\tzmappings。它是一个时区映射文件,一旦没有该文件就会发现时间操作上经常出现与正确时间相差几个小时的情况。下面是打包JRE中必不可少的文件列表(以Windows环境为例),其中[JRE]为运行环境的目录,同时这些文件之间的相对路径不能变。

文件名 目录

hpi.dll [JRE]\bin
ioser12.dll [JRE]\bin
java.dll [JRE]\bin
net.dll [JRE]\bin
verify.dll [JRE]\bin
zip.dll [JRE]\bin
jvm.dll [JRE]\bin\classic
rt.jar [JRE]\lib
tzmappings [JRE]\lib

由于rt.jar有差不多10MB,但是其中有很大一部分文件并不需要,可以根据实际的应用情况进行删除。例如程序如果没有用到Java Swing,就可以把涉及到Swing的文件都删除后重新打包。

阅读(274) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~