You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:06:08