亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Release<Type>ArrayElements 在 JNI 調用期間實際上沒有從堆中釋放內存?

Release<Type>ArrayElements 在 JNI 調用期間實際上沒有從堆中釋放內存?

小唯快跑啊 2023-06-21 15:31:45
我正在開發一個與一些本機 C++ 代碼 (JNI) 接口的 Android 應用程序。在 Java 方面,我將一個查找表(雙精度數組)和兩個 Open-CV 矩陣傳遞給 JNI(通過引用),然后使用 C++ 處理這些矩陣。雖然 JNI 函數調用在前 15~20 次有效,但應用程序很快就會崩潰并重新啟動。我 99% 確信這是我沒有正確釋放堆上內存的問題。我查看了 Profiler 以檢查內存的情況,發現每個 JNI 函數調用的內存使用量都在持續增加。大部分內存分配似乎都在 Native 部分,您可以在下圖中看到這種增加(增加與對 JNI 函數的調用一致)。extern "C" JNIEXPORT void JNICALLJava_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 循環之前“獲取”的雙數組,但似乎我們仍然有未釋放的內存。我還需要做其他事情才能正確釋放內存嗎?我還需要發布任何其他數據嗎?
查看完整描述

1 回答

?
MMMHUHU

TA貢獻1834條經驗 獲得超8個贊

我懷疑是釋放問題。


如果我有像這樣的超級簡單的Java代碼


package recipeNo026;


public class PassArray {


  public static native void passDoubleArray(double[] array);

  static { System.loadLibrary("PassArray"); }


  public static void main(String[] args) throws Exception {

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

      double[] doubleArray = new double[1_000_000_000];

      passDoubleArray(doubleArray);

      Thread.sleep(1000);

    }

  }

}

JNI本機代碼除了調用stuff之外沒有其他調用


JNIEXPORT void JNICALL Java_recipeNo026_PassArray_passDoubleArray

  (JNIEnv * env, jclass obj, jdoubleArray array) {


  printf ("Double array\n");

  jboolean isCopy;

  jdouble *doubleBody = (*env)->GetDoubleArrayElements(env, array, &isCopy);

  (*env)->ReleaseDoubleArrayElements(env, array, doubleBody, JNI_ABORT); 

}

Java 堆和本機代碼的內存消耗似乎都非常穩定。您可以看到代碼繼續運行時本機內存是如何分配和釋放的。

http://img1.sycdn.imooc.com//6492a78b0001ff0205930394.jpg

http://img1.sycdn.imooc.com//6492a7960001655405990119.jpg

我肯定會開始尋找從您的包裝器調用的部分代碼中的泄漏JNI。


另外,請注意這樣一個事實,即使您根本不調用本機代碼(例如JNI),本機內存也會增長。畢竟,Java 在某些時候必須使用malloc它自己的堆進行分配??纯催@里:


public static void main(String[] args) throws Exception {


    int size = 10;


    double [][] array = new double[100][1];


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

      array[i] = new double[size];

      size = size * 2;

      System.out.println("Allocating: " + size);

      Thread.sleep(1000);

    }


  }

沒有JNI電話了?,F在,讓我們運行該應用程序。


> java -Xmx4G -Xms512m -Djava.library.path=:./lib -cp target recipeNo026.PassArray

library: :./lib

Allocating: 20

Allocating: 40

Allocating: 80

Allocating: 160

Allocating: 320

Allocating: 640

Allocating: 1280

Allocating: 2560

Allocating: 5120

Allocating: 10240

Allocating: 20480

Allocating: 40960

Allocating: 81920

Allocating: 163840

Allocating: 327680

Allocating: 655360

Allocating: 1310720

Allocating: 2621440

Allocating: 5242880

Allocating: 10485760

Allocating: 20971520

Allocating: 41943040

Allocating: 83886080

Allocating: 167772160

Allocating: 335544320

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

    at recipeNo026.PassArray.main(PassArray.java:25)

讓我們看一下 Java 進程的本機內存消耗(隨著時間的推移)。

http://img1.sycdn.imooc.com//6492a7a700010afa13030274.jpg

查看完整回答
反對 回復 2023-06-21
  • 1 回答
  • 0 關注
  • 204 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號