Java Android JNI OutOfMemoryError

Java Android JNI OutOfMemoryError,java,android,opencv,java-native-interface,out-of-memory,Java,Android,Opencv,Java Native Interface,Out Of Memory,我的应用程序通过3321次迭代完成以下任务: 从SD卡加载图像(每次迭代中不同的图像) 调整图像大小 将一维数据从本机传递到Android 将1-d数据从Android传递到本机(以执行一些计算) 通过日志,我得到了以下信息: Progress: 1 / 3321 Progress: 2 / 3321 . . . Grow heap (frag case) to 5.597MB for 206132-byte allocation . . . Progress: X / 3321 Progres

我的应用程序通过3321次迭代完成以下任务:

  • 从SD卡加载图像(每次迭代中不同的图像)
  • 调整图像大小
  • 将一维数据从本机传递到Android
  • 将1-d数据从Android传递到本机(以执行一些计算)
  • 通过日志,我得到了以下信息:

    Progress: 1 / 3321
    Progress: 2 / 3321
    .
    .
    .
    Grow heap (frag case) to 5.597MB for 206132-byte allocation
    .
    .
    .
    Progress: X / 3321
    Progress: X+1 / 3321
    .
    .
    .
    Grow heap (frag case) to 64.000MB for 206132-byte allocation
    .
    .
    .
    FATAL EXCEPTION: Thread-451 Process: com.cv.myapp, PID: 15006
    java.lang.OutOfMemoryError 
    at com.cv.myapp.SecondModule.loadImg(Native Method)
    
    任务1、2和3由第二个模块完成,任务4由第一个模块完成

    在第二个模块中(用于加载图像、调整大小和传递一维数据):

    以及在我的第一个模块中执行任务4的本机函数:

    JNIEXPORT void JNICALL
    Java_cv_my_app_FirstModule_processImg(JNIEnv* env, jclass thiz,
        jfloatArray img) {
        // Get the image data (float array) passed from JAVA
        jboolean is_copied;
        jint img_size = env->GetArrayLength(img);
        jfloat* img_data = env->GetFloatArrayElements(img, &is_copied);
    
        // Do some calculation on variable img_data, 
        // and storing the result to the global variable.
    
        // Release the image data
        if (is_copied == JNI_TRUE)
            env->ReleaseFloatArrayElements(img, img_data, JNI_ABORT);
    }
    
    在Android中:

    FirstModule first_module = new FirstModule();
    SecondModule second_module = new SecondModule();
    
    // Load image paths into variable imgSet
    // Each image path can be retrieved by imgSet[i]
    
    // 3321 iterations
    for (int i=0 ; i<3321 ; ++i) {
        first_module.processImg(    
            second_module.loadImg( imgSet[i] )
        );
    }
    

    ,并打印以下日志。似乎发生了垃圾收集

    Progress: 301 / 3321
    
    Clamp target GC heap from 65.488MB to 64.000MB
    Grow heap (frag case) to 64.000MB for 206132-byte allocation
    
    Progress: 302 / 3321
    Progress: 303 / 3321
    
    Forcing collection of SoftReferences for 206132-byte allocation
    GC_BEFORE_OOM freed 61959K, 96% free 3192K/65408K, paused 21ms, total 24ms
    
    Progress: 304 / 3321
    Progress: 305 / 3321
    
    Grow heap (frag case) to 4.272MB for 206132-byte allocation
    
    Progress: 306 / 3321
    .
    .
    .
    
    在603迭代之后也发生了垃圾回收

    Progress: 603 / 3321
    
    Clamp target GC heap from 64.563MB to 64.000MB
    Grow heap (frag case) to 64.000MB for 206132-byte allocation
    
    Progress: 604 / 3321
    Progress: 605 / 3321
    Progress: 606 / 3321
    
    Forcing collection of SoftReferences for 206132-byte allocation
    GC_BEFORE_OOM freed 61219K, 87% free 3185K/24008K, paused 34ms, total 38ms
    Progress: 607 / 3321
    .
    .
    .
    
    但该应用程序在打印以下日志后崩溃

    Progress: 642 / 3321
    Grow heap (frag case) to 12.474MB for 206132-byte allocation
    Progress: 643 / 3321
    
    在日志“Progress:643/3321”之后没有其他日志

    编辑2:

    我补充说

    LOGI("Release Mat.");
    img.release();
    LOGI("Release Mat ... ok");
    
    以前

    return res;
    
    在第二个模块中

    日志显示

    I/SecondModuleJNI: Release Mat.
    I/SecondModuleJNI: Release Mat ... ok
    I/FirstModuleJNI: Progress: 1 / 3321
    I/dalvikvm-heap: Grow heap (frag case) to 4.816MB for 206132-byte allocation
    
    在应用程序崩溃之前

    if (is_copied == JNI_TRUE)
        env->ReleaseFloatArrayElements(img, img_data, JNI_ABORT);
    

    ReleaseFloatArrayElements()
    应该始终被调用,无论它是否被复制。否则,对数组的引用计数可能不会减少,并且无法进行垃圾收集。

    Mat img
    不会在您的第二个模块中发布。@DavidMiguel但只要它是重用对象的一个副本,就可以了。设置android:largeHeap=“true”如何
    return res;
    
    I/SecondModuleJNI: Release Mat.
    I/SecondModuleJNI: Release Mat ... ok
    I/FirstModuleJNI: Progress: 1 / 3321
    I/dalvikvm-heap: Grow heap (frag case) to 4.816MB for 206132-byte allocation
    
    if (is_copied == JNI_TRUE)
        env->ReleaseFloatArrayElements(img, img_data, JNI_ABORT);