Android JNI出坑指南

本文来自于腾讯Bugly公众号(weixinBugly), 作者:qingcuilu,未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/AtxEEN13z_sdbZTpJsKWLw

在Android编程中,出于硬件交互,跨平台,安全性,第三方库等方面的考虑,我们需要Java与C/C++互相调用,这就需要借助Java平台的JNI接口(Java Native Interface)。Android早期版本因JNI调用性能,native代码调试困难而被诟病,但近年来性能已经有不错的优化,Android NDK对C++开发支持也越来越好,特别是在Android Studio上开发调试C++代码极为方便。

然而JNI使用上还是有不少的坑和需要注意之处,特别是在多线程场景下使用JNI,不注意的话很容易出Bug。笔者结合自身经验、网上资料对JNI的坑进行总结,如果有不正确或遗漏之处欢迎指出。

局部引用超限

当我们通过FindClass,NewStringUtf等获取jclass或jobject,如果没有调用DeleteLocalRef删除局部引用,可能会出现内存泄漏或局部引用超限(local reference table overflow)的问题。

局部引用(Local Reference)是native code中对Java对象的映射,相当于持有一个Java对象的引用。局部引用属于JNI的引用类型,即是jobject或其子类。局部引用限于其创建的堆栈帧和线程,并且在其创建的堆栈帧返回时会自动删除。也就是说一般情况下局部引用会在返回Java方法时自己删除。但调用过程中如果存在循环、递归等调用层次过多的情况,很可能会导致局部引用数量超过局部引用限制导致崩溃。另一方面如果本地方法没有返回Java层,或本地线程没有断开与JVM的连接,局部引用无法自动释放会导致内存泄漏或局部引用超限的问题。

因此,我们定制规范,在局部引用使用完毕后,需要尽快调用DeleteLocalRef手动删除局部引用。

未调用DetachCurrentThread导致线程无法正常退出

在natvie线程中调用了AttachCurrentThread连接到虚拟机,但线程退出前未调用DetachCurrentThread取消连接,会导致线程无法正常退出,有类似错误日志:”thread exiting, not yet detached”,甚至导致VM abort。

JNIEnv是一个指向全部JNI方法的指针。该指针只在创建它的线程有效,不能跨线程传递。如果是从Java层通过native方法调用到C/C++方法,则会创建一个栈桢(stack frame)储存虚拟机相关信息,包括JNIEnv指针,即在native函数的入参处可获得。且此种情况不需要调用DetachCurrentThread取消连接。如果是在native层通过pthread_create等方式创建的线程,则需要调用了AttachCurrentThread连接到虚拟机,才能获取JNIEnv指针。且在线程退出前需要调用DetachCurrentThread取消连接。

因此,对于native线程,在调用JNI方法前可以先Attach,调用完成后立即Detach。不过这样手动调用显得较为繁琐。Google官方JNI指南文档建议在Android2.0以上可使用pthread_key,在线程析构时自动调用Detach以简化操作。

Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward, in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific to store the JNIEnv in thread-local-storage; t

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值