JNI中native层存储Java对象出现jobject失效崩溃该如何解决?
问题根因
JNI 规范中将引用分为三类:局部引用、全局引用、弱全局引用。你在 native 方法参数中拿到的 jobject 属于局部引用,它的生命周期仅局限于当前 native 方法的调用周期内:
- native 方法返回后,局部引用会被自动标记为失效
- JVM 的垃圾回收器不会感知 native 层是否还持有该局部引用的拷贝,会正常回收引用指向的 Java 对象
你后续访问已经失效的引用、指向已经被回收的对象内存,就会触发 JVM 的访问冲突错误。
错误操作点
你直接将方法参数传入的局部引用 value 赋值给全局变量 car,没有将其转换为生命周期更长的引用类型,导致方法退出后全局变量存储的引用直接失效。
正确实现方案
需要将局部引用转换为全局引用,全局引用跨 native 方法调用、跨线程有效,且会阻止 JVM 回收指向的 Java 对象,直到你手动释放该引用。
修改后的 com_gabrik_gabos_Main.cpp 代码如下:
#include "pch.h" #include "com_gabrik_gabos_Main.h" jobject car = nullptr; JNIEXPORT void JNICALL Java_com_gabrik_gabos_Main_saveCar (JNIEnv* env, jclass cls, jobject value) { // 先释放之前存储的旧全局引用,避免内存泄漏 if (car != nullptr) { env->DeleteGlobalRef(car); car = nullptr; } // 将局部引用转换为全局引用后再存储 car = env->NewGlobalRef(value); } JNIEXPORT jobject JNICALL Java_com_gabrik_gabos_Main_getSavedCar (JNIEnv* env, jclass cls) { return car; }
注意事项
- 当你后续不再需要存储的
Car对象时,必须主动调用env->DeleteGlobalRef(car)释放全局引用,否则该对象永远不会被 JVM 回收,会造成内存泄漏 - 如果不需要阻止对象被 GC 回收,仅需要判断对象是否存活,可以选择使用
NewWeakGlobalRef创建弱全局引用
内容的提问来源于stack exchange,提问作者user14787178
相关产品推荐
相关产品推荐

