java JNI编程指南 下载本文

1、

制。 2、

如果GC支持pin,并且数组的布局和本地相同类型的数组布局一样,就不会发生复否则的话,数组被复制到一个不可变的内存块儿中(例如,C的heap上面)并做一

些格式转换。并把复制品的指针返回。

当数组使用完后,本地代码会调用另外一组函数(例如,ReleaseInt-ArrayElement)来通知JVM。这时,JVM会unpin数组或者把对复制后的数组的改变反映到原数组上然后释放复制后的数组。 这种方式提供了很大的灵活性。GC算法可以自由决定是复制数组,或者pin数组,还是复制小数组,pin大数组。

JNI函数必须确保不同线程的本地方法可以同步访问相同的数组。例如,JNI可能会为每一个被pin的数组保持一个计数器,如果数组被两个线程pin的话,其中一个unpin不会影响另一个线程。

11.7.2 字段和方法

JNI允许本地代码通过名字和类型描述符来访问JAVA中的字段或调用JAVA中的方法。例如,为了读取类cls中的一个int实例字段,本地方法首先要获取字段ID:

jfieldID fid = env->GetFieldID(env, cls, \

然后可以多次使用这个ID,不需要再次查找:

jint value = env->GetIntField(env, obj, fid);

除非JVM把定义这个字段和方法的类或者接口unload,字段ID和方法ID会一直有效。 字段和方法可以来自定个类或接口,也可以来自它们的父类或间接父类。JVM规范规定:如果两个类或者接口定义了相同的字段和方法,那么它们返回的字段ID和方法ID也一定会相同。例如,如果类B定义了字段fld,类C从B继承了字段fld,那么程序从这两个类上获取到的名字为“fld”的字段的字段ID是相同的。

JNI不会规定字段ID和方法ID在JVM内部如何实现。

通过JNI,程序只能访问那些已经知道名字和类型的字段和方法。而使用Java Core Reflection机制提供的API,程序员不用知道具体的信息就可以访问字段或者调用方法。有时在本地代码中调用反射机制也很有用。所以,JDK提供了一组API来在JNI字段ID和java.lang.reflect.Field类的实例之间转换,另外一组在JNI方法ID和java.lang.reflect.Method类实例之间转换。

11.8 错误和异常

JNI编程时的错误通常是JNI函数的误用导致的。比如,向GetFieldID方法传递一个对象引用而不是类引用等。

11.8.1 不检查编程错误

JNI函数不对编程错误进行检查。向JNI函数传递非法参数会导致未知的行为。原因如下: 1、 2、

强制JNI函数检查所有可能的错误会减慢所有本地方法的执行效率。 大部分情况下,运行时没有足够的类型信息来做错误检查。

大部分的C库函数也同样对编程错误不做预防。例如printf这个函数,当接收到非法的参数时,它会引发一起运行时错误,而不会抛出错误码。强制C库函数检查所有可能的错误会导致错误被重复检查,一次是在用户代码中,一次是在库函数中。

虽然JNI规范没有要求VM检查编程错误,但鼓励VM对普通错误提供检查功能。例如,VM在使用JNI函数表的调用版本时可能会做更多的错误检查。

11.8.2 JVM异常

一旦JNI发生错误,必须依赖于JVM来处理异常。通过调用Throw或者ThrowNew来向JVM抛出一个异常。一个未被处理的异常会记录在当前线程中。和JAVA中的异常不同,本地代码中的异常不会立即中断当前的程序执行。

本地代码中没有标准的异常处理机制,因此,JNI程序最好在每一步可能会产生异常的操作后面都检查和处理异常。JNI程序员处理异常通常有两种方式: 1、 2、

本地方法可以选择立即返回。让代码中抛出的异常向调用者抛出。

本地代码可以通过调用ExceptionClear清理异常并运行自己的异常处理代码。

异常发生后,一定要先进行处理或者清除后再进行后续的JNI函数调用。大部分情况下,调用一个未被处理的异常都可能会一个未定义的结果。下面列表中的JNI函数可以在发生异常后安全地调用:

? ? ? ? ? ? ? ? ? ? ? ? ?

?

最前面的四个函数都是用来做异常处理的。剩下的都是用来释放资源的,通常,异常发生后都需要释放资源。

11.8.3 异步异常

本节已经过时,不再翻译。

ExceptionOccurred ExceptionDescribe ExceptionClear ExceptionCheck

ReleaseStringChars ReleaseStringUTFchars ReleaseStringCritical ReleaseArrayElements

ReleasePrimitiveArrayCritical DeleteLocalRef DeleteGlobalRef DeleteWeakGlobalRef MonitorExit