所有内容为记录学习过程,不是大牛尽情谅解。所有分析都参考深入理解Android 卷一
Java中创建的对象最后由垃圾回收期来回收和释放内存,对于JNI这有什么影响呢?
结合书上的例子分析(下面的例子是他假设的例子并不是真正的源码)
Android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz,jstring path, jstring mimeType, jobject client)
{
。。。。。。;
//保存Java层换入的jobject对象,代表MediaScanner对象
Save_this = thiz;
。。。。。。;
Return;
}
//假设在某个时间,有地方调用callMediaScanner函数
Void callMediaScanner(){
//在这里操作save_thiz,是否会有问题
}
上面肯定是有问题的,save_thiz对应java层中的MediaScanner 很有可能已经被回收了,也就是说save_thiz保存的jobject 可能已经是野指针。
这里插入一点知识(我也不是太懂)对于一个引用类型的执行操作,它的引用计数不会增加吗?
而垃圾回收机制,只会保证哪些没有被引用过的对象才会被清理。但在JNI中,下面这句不会增加引用计数
save_thiz = thiz; 这种赋值不会增加引用计数
引用计数没有增加 thiz就可能被回收。幸运的是JNI 规范已经很好的解决了这一问题
JNI计数提供了三种引用计数
1,Local Reference 本地引用,jni层函数使用的非全局引用对象都是local reference
包括函数调用时传入的jobject和在JNI层函数中创建的jobject,local Reference 最大的特点就是 一旦JNI层函数回收,这些jobject就可能被垃圾回收了。
2,Global Reference 全局引用,这种对象如不主动释放,它永远不会被垃圾回收。
3WeakGlobal Reference 弱全局引用,一种特殊的Global Reference 在运行过程中可能会被垃圾护手,所以再使用它之前需要用JNIEnv的IsSameObject判断是否被回收
看下面代码例子
Ok mClient 不用害怕被回收了
成对出现 你懂得!
想在JNI中保存某个对象 就用 Global Reference 使用完释放就OK了。
这里获取的pathStr 就是一个local Reference 这个函数返回后,该变量就被回收,看上去下面的mEnv->DeleteLocalRef(pathStr);看上去是多余的,其实还是有用的。
1,如果不调用哪个DeleteLocalRef,pathStr将在函数返回后背回收。
2,如果调用DeleteLocalRef, pathStr会被立即回收,这两者看起来差不多。
但是在某些情况的时候 内存很快就会被耗尽,举例
For(int i = 0;i < 100 ; i++){
Jstring pathStr = mEnv->NewStringUTF(path);
做一些操作
}
return ;
如果上面哪个循环中不用DeleteLocalRef则会创建100个jstring 那么内存耗费就非常可观了。
谁污染谁治理,谁创建谁回收,主动调用还是有好处的,细心每一个细节。