关于local jni handle和global jni handle在这里有比较详细的解释。
举个例子,下面的代码创建了一个int[],然后赋值给arr。
void foo(){
int[] arr = (int[]) Array.newInstance(int.class,4);
}
其中Array.newInstance会调用一个JNI函数,创建数组:
JVM_ENTRY(jobject, JVM_NewArray(JNIEnv *env, jclass eltClass, jint length))
JVMWrapper("JVM_NewArray");
JvmtiVMObjectAllocEventCollector oam;
oop element_mirror = JNIHandles::resolve(eltClass);
oop result = Reflection::reflect_new_array(element_mirror, length, CHECK_NULL);
return JNIHandles::make_local(THREAD, result);
JVM_END
可以杠一下:为什么不直接返回result,而是要返回JNIHandles::make_local呢,两者都是返回的jobject类型。
最主要的原因是,JVM要跟踪这个对象是否被使用。上面的代码中,Reflection::reflect_new_array创建一个指针,然后赋值给oop result(oop是一个指针),假如直接return result给java代码用,这个时候result指针在rax里面,然后会放到java frame里面,如果这个result在放到java frame这个过程中发生了gc移动对象,那么就会导致rax放到java frame的是一个指向无效数据的指针,导致问题。(如果已经放到java frame了,那就没什么问题了,因为gc移动对象的同时会更新java frame的指向)。所以出于这个问题,必须要用jni handle包装一下对象。