JNI学习三(Local references & Global references 以及JNI内存泄露)

Local Reference 和 Global Reference

JNI支持三种类型的opaquereference:local references, global references和weak globalreferences

 

Local reference 只在本线程的nativemethod中有效,native method返回到Java层时将自动释放。一般是JNI自动创建。

主动调用DeleteLocalRef:LocalRef是阻止引用被GC,但是当你在本地代码中操作大量对象时,而LocalRefTable又是有限的,及时调用DeleteLocalRef,会释放LocalRef在LocalRefTable中所占位置并使对象及时得到回收。

 

GlobalRef可以在多个本地方法调用过程和多线程中使用,需要通过NewGlobalRef和DeleteGlobalRef主动创建和删除。

Weak Global Reference用NewGlobalWeakRef和DeleteGlobalWeakRef进行创建和删除,与GlobalRef的区别在于该类型的引用不保证不被GC。

 

// 比较两个对象的相容性, 返回值:JNI_TRUE,JNI_FALSE

(*env)->IsSameObject(env, obj1,obj2);

对于Weak Global Ref来说,需要通过如下代码来判定,因为其可能指向已经被GC的无效对象:(*env)->IsSameObject(env, wobj, NULL);

 

Push/PopLocalFrame常被用来管理LocalRef,在进入本地方法时,调用一次PushLocalFrame,本地方法结束时调用PopLocalFrame,此对方法执行效率非常高。

JNI之内存泄漏

JAVA中的内存泄漏,从泄漏的内存位置角度,可以分为:

1、  JVM中Java Heap的内存泄漏;

2、  JVM内存中native memory的内存泄漏。

 

Java Heap中out of memory异常的出现有两种原因:1、程序过于庞大,致使过多Java对象的同时存在;2、程序编写的错误导致JavaHeap内存泄漏

 

Java Heap以外的内存空间称为JVM的nativememory

 

Native memory的内存泄漏:

1、  Native code本身的内存泄漏

2、  Global Reference引入的内存泄漏。需要主动删除引用,否则,其引用的Java对象将永远停留在Java Heap中,造成Java Heap的内存泄漏

3、  Local Reference引入的内存泄漏。Local Reference在native method执行完成后,会自动被释放,但也会有可能引发内存泄漏,需重点关注。

 

Local Reference 相关实例:

1、  在nativemethod中,循环的创建对象,导致out of memory

jstring str

for(i= 0; I < 100000; i++) {

           str =NewStringUTF(env, “000”);

}

过多的Local Reference,导致了JNI内部的JNI Local Reference表内存溢出

 

2、  如下,通过调用函数的方式,CreateStringUTF返回后,似乎会释放LocalReference

jstring CreateStringUTF(JNIEnv * env) {

return (*env)->NewStringUTF(env,"0");

}

然后在native method中循环调用此函数。

Local Reference 和局部变量有着本质的区别。

 

JNI Local Reference 的生命期是在 nativemethod 的执行期(从 Java 程序切换到 native code 环境时开始创建,或者在 native method 执行时调用 JNI function 创建),在 native method 执行完毕切换回 Java 程序时,所有 JNI Local Reference 被删除,生命期结束(调用 JNI function 可以提前结束其生命期)。

 

实际上,每当线程从 Java 环境切换到 native code 上下文时(J2N),JVM 会分配一块内存,创建一个 Local Reference 表,这个表用来存放本次 native method 执行中创建的所有的 Local Reference。每当在 native code 中引用到一个 Java 对象时,JVM 就会在这个表中创建一个 Local Reference。比如,实例 1 中我们调用 NewStringUTF() 在 Java Heap 中创建一个 String 对象后,在 Local Reference 表中就会相应新增一个 Local Reference。

 

Local Reference 表、Local Reference 和 Java 对象的关系


上图中:

⑴运行 nativemethod 的线程的堆栈记录着 Local Reference 表的内存位置(指针 p)。

         ⑵Local Reference 表中存放 JNI Local Reference,实现 Local Reference 到 Java 对象的映射。

         ⑶native method 代码间接访问 Java 对象(java obj1,java obj2)。通过指针 p 定位相应的 Local Reference 的位置,然后通过相应的 Local Reference 映射到 Java 对象。

         ⑷当 nativemethod 引用一个 Java 对象时,会在 Local Reference 表中创建一个新 Local Reference。在 Local Reference 结构中写入内容,实现 Local Reference 到 Java 对象的映射。

         ⑸native method 调用 DeleteLocalRef() 释放某个 JNI Local Reference 时,首先通过指针 p 定位相应的 Local Reference 在 Local Ref 表中的位置,然后从 Local Ref 表中删除该 Local Reference,也就取消了对相应 Java 对象的引用(Ref count 减 1)。

         ⑹当越来越多的 LocalReference 被创建,这些 Local Reference 会在 Local Ref 表中占据越来越多内存。当 Local Reference 太多以至于 Local Ref 表的空间被用光,JVM 会抛出异常,从而导致 JVM 的崩溃。

 

Local Ref 不是 native code 的局部变量

Native Code 的局部变量和 LocalReference 是完全不同的,区别可以总结为:

         ⑴局部变量存储在线程堆栈中,而 Local Reference 存储在 Local Ref 表中。

         ⑵局部变量在函数退栈后被删除,而 Local Reference 在调用 DeleteLocalRef() 后才会从 Local Ref 表中删除,并且失效,或者在整个 Native Method 执行结束后被删除。

         ⑶可以在代码中直接访问局部变量,而 Local Reference 的内容无法在代码中直接访问,必须通过 JNI function 间接访问。JNI function 实现了对 Local Reference 的间接访问,JNI function 的内部实现依赖于具体 JVM。

 

         代码 str =(*env)->NewStringUTF(env, "0");

         str是 jstring 类型的局部变量。Local Ref 表中会新创建一个 Local Reference,引用到 NewStringUTF(env, "0") 在 Java Heap 中新建的 String 对象。如下图所示:



  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值