Release<Type>ArrayElements 在 JNI 调用期间实际上没有从堆中释放内存?

我正在开发一个与一些本机 C++ 代码 (JNI) 接口的 Android 应用程序。在 Java 方面,我将一个查找表(双精度数组)和两个 Open-CV 矩阵传递给 JNI(通过引用),然后使用 C++ 处理这些矩阵。虽然 JNI 函数调用在前 15~20 次有效,但应用程序很快就会崩溃并重新启动。我 99% 确信这是我没有正确释放堆上内存的问题。

我查看了 Profiler 以检查内存的情况,发现每个 JNI 函数调用的内存使用量都在持续增加。大部分内存分配似乎都在 Native 部分,您可以在下图中看到这种增加(增加与对 JNI 函数的调用一致)。

http://img4.mukewang.com/6492a7790001337006540208.jpg

extern "C" JNIEXPORT void JNICALL

Java_com_mygroup_productName_ImgProcUtils_interpVals(

        JNIEnv *env,

        jobject /* this */,

        jlong addrKSqrd,

        jint nRows,

        jint nCols,

        jdoubleArray yTaucVal,

        jlong addrTauc) {

    cv::Mat& kSqrd = *(cv::Mat*)addrKSqrd;

    cv::Mat& Tauc = *(cv::Mat*)addrTauc;

    jboolean isCopy;

    jdouble *elem = env->GetDoubleArrayElements(yTaucVal, &isCopy);

    float pixel;

    for (int i = 0; i < nRows; i++) {

        for (int j = 0; j < nCols; j++) {

            pixel = kSqrd.at<float>(i, j);

            int value = (int)round(pixel * 65535);

            if (value < 0) {

                value = 0;

            } else if (value > 65535) {

                value = 65535;

            }

            Tauc.at<float>(i,j) = (jfloat)elem[value];

        }

    }

    env->ReleaseDoubleArrayElements(yTaucVal, elem, JNI_ABORT);

}


正如您所看到的,我正在释放 for 循环之前“获取”的双数组,但似乎我们仍然有未释放的内存。我还需要做其他事情才能正确释放内存吗?我还需要发布任何其他数据吗?


小唯快跑啊
浏览 160回答 1
1回答

MMMHUHU

我怀疑是释放问题。如果我有像这样的超级简单的Java代码package recipeNo026;public class PassArray {&nbsp; public static native void passDoubleArray(double[] array);&nbsp; static { System.loadLibrary("PassArray"); }&nbsp; public static void main(String[] args) throws Exception {&nbsp; &nbsp; for(int i=0; i<100; i++) {&nbsp; &nbsp; &nbsp; double[] doubleArray = new double[1_000_000_000];&nbsp; &nbsp; &nbsp; passDoubleArray(doubleArray);&nbsp; &nbsp; &nbsp; Thread.sleep(1000);&nbsp; &nbsp; }&nbsp; }}JNI本机代码除了调用stuff之外没有其他调用JNIEXPORT void JNICALL Java_recipeNo026_PassArray_passDoubleArray&nbsp; (JNIEnv * env, jclass obj, jdoubleArray array) {&nbsp; printf ("Double array\n");&nbsp; jboolean isCopy;&nbsp; jdouble *doubleBody = (*env)->GetDoubleArrayElements(env, array, &isCopy);&nbsp; (*env)->ReleaseDoubleArrayElements(env, array, doubleBody, JNI_ABORT);&nbsp;}Java 堆和本机代码的内存消耗似乎都非常稳定。您可以看到代码继续运行时本机内存是如何分配和释放的。我肯定会开始寻找从您的包装器调用的部分代码中的泄漏JNI。另外,请注意这样一个事实,即使您根本不调用本机代码(例如JNI),本机内存也会增长。毕竟,Java 在某些时候必须使用malloc它自己的堆进行分配。看看这里:public static void main(String[] args) throws Exception {&nbsp; &nbsp; int size = 10;&nbsp; &nbsp; double [][] array = new double[100][1];&nbsp; &nbsp; for(int i=0; i<100; i++) {&nbsp; &nbsp; &nbsp; array[i] = new double[size];&nbsp; &nbsp; &nbsp; size = size * 2;&nbsp; &nbsp; &nbsp; System.out.println("Allocating: " + size);&nbsp; &nbsp; &nbsp; Thread.sleep(1000);&nbsp; &nbsp; }&nbsp; }没有JNI电话了。现在,让我们运行该应用程序。> java -Xmx4G -Xms512m -Djava.library.path=:./lib -cp target recipeNo026.PassArraylibrary: :./libAllocating: 20Allocating: 40Allocating: 80Allocating: 160Allocating: 320Allocating: 640Allocating: 1280Allocating: 2560Allocating: 5120Allocating: 10240Allocating: 20480Allocating: 40960Allocating: 81920Allocating: 163840Allocating: 327680Allocating: 655360Allocating: 1310720Allocating: 2621440Allocating: 5242880Allocating: 10485760Allocating: 20971520Allocating: 41943040Allocating: 83886080Allocating: 167772160Allocating: 335544320Exception in thread "main" java.lang.OutOfMemoryError: Java heap space&nbsp; &nbsp; at recipeNo026.PassArray.main(PassArray.java:25)让我们看一下 Java 进程的本机内存消耗(随着时间的推移)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java