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 或许是进程占用内存过多的一个原因,平时使用要注意。

 

posted @ 2015-09-07 15:04  supersheep6  阅读(858)  评论(0)    收藏  举报