JNI内存管理之Local Reference 和 Global Reference知识点

最近开发过程中遇到了JNI的Reference相关问题,了解到Local Reference和Global Reference的相关知识点,整理如下:

背景:项目需求,在Native C/C++层调用上层Android Camera Java接口,把所有的操作包括Camera都沉到Native层去实现。但在JNI调试过程中遇到了android JNI ERROR (app bug): accessed stale local reference的报错。

现象:在Native层创建Java的Camera对象,其对象的指针保存到本地,函数返回到Java层,之后再进入Native层,想通过Native层的Camera对象指针调用相应的方法,但是发现每次都是重新调用Java对象方法后报错。

分析:在Native层创建的Java对象,对象创建后会有一个局部引用指向该对象,当从Native环境返回到Java环境,该局部引用失效,此对象就没有引用计数,Java的内存回收机制会自动回收该对象,第二次再进入Native层访问其之前保存的地址时就会报错。

解决:使用全局引用始终持有该对象的引用使其不被自动回收,请看下面的知识点。

Local Reference

局部引用,看如下精简代码:

env->NewStringUTF("0"); 

在JNI中,每次调用NewObject方法创建一个新的对象都会返回一个对该对象的局部引用(Local Reference),该局部引用只在线程当前的Native环境中有效,返回到Java环境后该引用与对象之间的联系就会被断掉,引用失效,所以我们不能在Native方法中把局部引用缓存用于下一次调用时使用。

局部引用可以无限创建吗

如图:

局部引用表

这里引入局部引用表的概念,每当线程从Java环境进入到Native环境后,JVM就会创建该线程Native环境的局部引用表,用来保存本次Native环境所创建的所有局部引用,每当Native中引用或者新创建一个Java对象,JVM就会局部引用表创建一个局部引用,局部引用表是有大小限制的,最大是512,如果超过限制会报OOM内存泄漏。

Q:那如何才能更好的避免由于局部引用过多造成Native环境中的OOM呢?

A:控制局部引用的生命周期,如果需要创建过多的局部引用,可以在Java对象的操作结束后,手动调用DeleteLocalRef函数删除局部引用,该局部引用就会在局部引用表中被移除,避免触发局部引用表的大小限制。

注意:局部引用不是我们平时所理解的代码中的局部变量,局部变量在当前生命周期(例如函数退出)结束后就会失效,而局部引用在函数退出后可能不会失效,它的生命周期是和整个Native上下文环境相关联,只有从Native环境返回到Java环境后局部引用才会失效。

Global Reference

全局引用,终于到了最上面讨论的问题了,因为局部引用在Native环境返回到Java环境后就会失效,导致下次进入Native环境后再次使用相对应的Java对象就会出错,所以可以使用全局引用来解决这个问题,全局引用可以始终与Java对象保持联系,使得此对象不会被JVM回收掉,见如下代码:

JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * reserved) {  
    jclass tmp = env->FindClass("com/example/company/MyClass");  
    jclass class = env->NewGlobalRef(tmp);
    return JNI_VERSION_1_6;  
}

这里需要注意,在不需要使用Java对象后尽量手动调用DeleteGlobalRef()函数来使得引用失效,避免对象始终存在,产生潜在的内存泄漏。

Weak Global Reference

虚全局引用与全局引用的区别在于该类型的引用可能随时被JVM回收掉,这里涉及到几个函数:

NewWeakGlobalRef();
DeleteWeakGlobalRef();
isSameObject();

在使用虚引用前需要通过isSameObject将其和NULL比较,如果返回TRUE返回true表示已经被JVM回收掉就不能使用了,这里有可能前一行代码判断还是可用,后一行代码时就被JVM回收,解决办法时通过NewLocalRef()获取虚全局引用,避免当时被JVM回收。

参考资料

https://www.cnblogs.com/zhongshujunqia/p/4638077.html?utm_source=tuicool&utm_medium=referral
https://www.cnblogs.com/younghome/p/4609044.html
https://stackoverflow.com/questions/14765776/jni-error-app-bug-accessed-stale-local-reference-0xbc00021-index-8-in-a-tabl
https://www.ibm.com/developerworks/cn/java/j-lo-jnileak/index.html
https://juejin.im/post/5c19bfa0f265da6133568545

更多文章请关注

programmersmall.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353