JNI中的一对GetStringCritical、ReleaseStringCritical引发的知识盲区

JNI中很多概念与JVM的内存和引用使用模型有关。

GetStringCritical
ReleaseStringCritical必须成对出现。而且不能跨线程,之间不能调用其他JNI方法,只能进行CPU计算,不能发生IO和任何阻塞。

这么严格的使用限制,自然会有疑问,为什么还要设计它们?

为了极高效的遍历数组数据,中间不产生内存copy以最大限度的提高效率。

其中涉及JVM垃圾回收过程中的移动对象的概念,为了减少内存的碎片化,使内存访问保持高效,JVM垃圾回收会对内存区进行对象移动。而Critical家庭的JNI操作就是告诉JVM将一些对象进行标记,从而实现native裸指针地址不变,从而可以对大字符串等对象进行高效无copy操作。

其中关键是对象移动影响native裸指针所指向的对象被移动的新地址,而native裸指针不能像java层那样由引用表(中间层)进行自动同步,所以native指针在对象移动后就不能再指向原对象了,java引用却可以,这正是JVM运行时中间层起到的作用。

java层调入native层,传递的jobject两层都是同一个java对象的句柄。我理解此时的jobject在native层是本地引用LocalRef的概念,一次jni调用结束返回时即会自动回收掉。如果想随时控制其生命周期结束,则对其使用NewLocalRef或GlobalRef从而可以调用LocalRef或GlobalRef相应的release方法即可释放资源,从而让JVM对其进行正常垃圾收集和回收资源。

LocalRef及GlobalRef的存在是将jobject加入到生命周期、使用线程、jni调用管理中。前者不能跨线程使用,也不能跨jni调用过程使用(一次jni调用过程),都要有对应的release调用来保证内存不溢出。

native裸指针没有JVM来自动更新对象移动后的新地址,这是与java从设计上不同的地方,是对内存的直接使用。JNI中,java对象的句柄一般经过特定的JNI方法调用后才会从句柄转变到nativer祼指针,这个转变点是关键节点。如

字符串

  • GetStringChars

  • GetStringUTFChars

  • GetStringCritical

数组

  • GetIntArrayElements

  • GetPrimitiveArrayCritical

NIO Buffer

  • GetDirectBufferAddress

这些JNI方法返回的都是裸指针。可以理解为只有经过这些调用后才会涉及到JVM移动对象影响到native指针的使用。

GetStringCritical得到的是所谓内部buffer,即是JVM直接暴露的对象内存,为了避免开发者代码对内存的破坏性影响,所以在使用时要求不能阻塞不能作其他jni调用等,进行保护。

涉及的知识有点多,所以记录一下,留个思考路线以便回忆。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值