JNI中垃圾回收相关知识
我们知道,java中创建对象后是可能被垃圾回收器回收掉,那会对JNI有什么影响?看下面这个例子:
1 static jobject save_thiz=NULL; //定义一个全局的jobject 2 static void android_media_MediaScanner_processFile(JNIEnv *env,jobject thiz,jstring path,jstring mimeType,jobject client) 3 { 4 .... 5 //保存java层传入的jobject对象 6 save_thiz=thiz; 7 .... 8 return; 9 10 } 11 12 void callMediaScanner(){ 13 // 在这里调用对象save_thiz,会不会有问题? 14 15 }
上面的做法肯定有问题,因为save_thiz对应的java层中的MediaScanner很有可能已经被垃圾回收了,也就是说save_thiz保存的jobject可能是一个野指针。。。使用之,后果很严重。
像save_thiz=thiz;这种写法是不会增加计数引用的,所以JNI技术提供了自己的三种类型的引用,以解决这类问题。
- Local Reference :本地引用。在JNI层函数中使用的非全局引用对象都是Local Reference,其中在函数调用时传入的jobject和在JNI层创建的jobject都是这种类型。其最大的特点是,一旦JNI函数返回,这些jobject就可能被垃圾回收。
- Global Reference :全局引用,这种对象如果不主动释放,它永远不会被回收。
- Weak Global Reference : 弱全局引用,这种特殊的全局引用,在运行过程中可能会被垃圾回收,所以在使用前,先调用JNIEnv的 IsSameObject 判断它是否被回收了!
当然平时用的最多的是前两种。下面看一下代码示例。
Global Reference的示例:
1 // android_media_MediaScanner.cpp::MyMediaScannerCilent的构造函数 2 MyMediaScannerClient(JNIEnv *env,jobject client):mEnv(env), 3 // 调用 NewGlobalRef创建一个Global Reference ,这样mClient就不用担心被回收了 4 mClient(env->NewGlobalRef(client)),mScannerFileMethodID(0), 5 mHandleStringTagMethodID(0), 6 mSetMimeTypeMethodID(0) 7 { 8 ........ 9 } 10 11 // 析构函数 12 Virtual -MyMediaScannerClient() 13 { 14 mEnv->DeleteGolbalRef(mClient);// 释放全局引用 15 16 }
当想要在JNI层保存java层的某个对象时,就用Global Reference保存,使用完后记住释放就可以了。
Local Reference :
1 virtual bool scanFile (const char* path,long long lastModified,long long fileSize) 2 { 3 jstring pathStr; 4 ............. 5 6 for(int i=0;i<100;i++){ 7 jstring pathStr = mEnv->NewStringUTF(path); 8 ..... 9 // mEnv->DeleteLocalRef(pathStr);//不立即释放Local Ref 10 } 11 12 // 上面如果不立即释放Local Reference ,则会创建100个jstring,那么内存消耗就很可观了!!! 13 14 ............... 15 16 }
所以,没有及时回收Local Reference 或许是进程占用内存过多的一个原因,平时使用要注意。

浙公网安备 33010602011771号