在JNI的C++代码中创建New<PrimitiveType>Array后,如何释放其缓冲区?
解决JNI中
NewIntArray引发的内存泄漏问题 嘿,我来帮你理清这个问题——你遇到的崩溃和内存泄漏,核心是对JNI数组引用的生命周期理解错了,误用了Release系列方法。
首先说崩溃的原因:ReleaseIntArrayElements这个方法只用来释放通过GetIntArrayElements拿到的原生数组指针,根本不是给NewIntArray创建的JNI数组用的,你这么调用肯定会崩,完全是用错API了。
接下来聊内存泄漏的根源和正确的解决方式:
1. 先搞懂JNI数组引用的生命周期
你用NewIntArray创建的jintArray par属于JNI局部引用:
- 正常情况下,局部引用会在当前JNI函数执行完、返回给Java层的时候,被虚拟机自动回收。
- 但如果你的
setDisplay被高频调用,或者当前JNI线程一直附着在VM上(比如循环调用这个函数,没机会回到Java层),这些局部引用就会堆积起来,虚拟机来不及自动回收,最终导致内存泄漏。
2. 正确的释放姿势
在用完jintArray之后,手动调用DeleteLocalRef释放这个局部引用,就能避免堆积。修改后的代码如下:
void Display::setDisplay(vector<uint32_t>& a) { jint* buffer = new jint[a.size()]; for(int i = 0; i < a.size(); i++) buffer[i] = (jint)a[i]; jintArray par = java.env->NewIntArray(a.size()); java.env->SetIntArrayRegion(par, 0, a.size(), buffer); java.env->CallVoidMethod(displayObject, setDisplay_, par); // 手动释放jintArray的局部引用,避免堆积 java.env->DeleteLocalRef(par); delete[] buffer; // 注意这里要用delete[],因为你new的是数组!之前的delete其实是错的,也可能导致泄漏 }
额外优化:不用手动管理buffer内存
其实你可以用vector<jint>来替代手动new数组,这样不用自己管delete,更安全:
void Display::setDisplay(vector<uint32_t>& a) { size_t arrSize = a.size(); vector<jint> buffer(arrSize); for(size_t i = 0; i < arrSize; i++) buffer[i] = (jint)a[i]; jintArray par = java.env->NewIntArray(arrSize); java.env->SetIntArrayRegion(par, 0, arrSize, buffer.data()); java.env->CallVoidMethod(displayObject, setDisplay_, par); java.env->DeleteLocalRef(par); }
3. 再强调一遍API的正确配对
别再搞混了:
GetIntArrayElements↔ReleaseIntArrayElements:这是一对,用来获取Java数组的原生内存指针,用完后归还给虚拟机。NewIntArray↔DeleteLocalRef:创建新的Java数组对象后,用DeleteLocalRef释放它的JNI局部引用。
内容的提问来源于stack exchange,提问作者TenebrisLux
相关产品推荐
相关产品推荐

