android 內存泄露之jni local reference table overflow (max=512)

轉自:https://www.cnblogs.com/lzl-sml/p/3520052.html

在android項目中要實現一個需求

爲了性能的要求只能用c代碼來實現功能。

這樣就犧牲了java跨平臺性。

通過加載.so的方式,把用c實現的模塊集成到app中。

android提供jni層,作爲一個適配器。

可以在java層調用c接口,在jni層可以通過java提供的反射機制調用java接口和創建java對象。

最後需求完成了,自測也沒問題,嘻嘻,自己也開心了一下,但是提交測試後,測試人員馬上報了一個bug。

出現local reference table overflow (max=512)這樣的一個錯誤。我去,盡然出現了崩潰。

google和百度了半天,才發現原來發生了jni層的內存泄露,導致了崩潰。

jni層到底出現了啥內存泄露????

從java代碼進入jni層本地代碼調用時,Dalvik就創建了一張local reference表來存儲local reference,這張表

的表項數有最大值限制,一般最大爲都是512個,local reference表只有當退出jni層代碼的調用是纔會清除掉。

當表項數超過最大值限制時,Dalvik就會拋出異常,導致了崩潰。

何爲local reference????

他是在native代碼層他是一個本地變量和java對象的引用。

JNIEXPORT jint JNICALL Java_com_print(JNIEnv *env, jobject obj){

  char data[] = "daffdasf";

    jstring content = (*env)->NewStringUTF(env, data);

}

變量content在 函數Java_com_print中是一個本地變量並且是String對象一個引用。所以會在local reference table

中追加一個表項來指向java對象。

其實每次進入native代碼都會存在一個全局指向local reference table起始位置的ptr變量。

而上面函數中的content只是代表一個在local reference table中的偏移,通過ptr + content偏移

從local reference table獲取java對象的值。

什麼原因會發生local reference table overflow?????

那就是在一個循環中不斷的創建local reference,而沒有調用DeleteLocalRef去銷燬這個local reference,

從而導致local reference table中表項不斷增加,最後超過最大值,抱出了異常,導致了崩潰。

舉兩個例子哈:

例子1.

JNIEXPORT jint JNICALL Java_com_example(JNIEnv *env, jobject obj){

  char data[] = "daffdasf";

  int i = 0;

  for(i = 0;i < 1000;i++){

    jstring content = (*env)->NewStringUTF(env, data);

  }

}

例子1代碼會導致local reference table overflow

例子2.

int Java_com_example(char * data){

   JNIEnv *env = NULL;
   JavaVM * vm = NULL;

  vm = getVm();

  (*vm)->AttachCurrentThread(vm, &env, NULL);

     jstring content = (*env)->NewStringUTF(env, data);

}

void callExample(){

  int i = 0;

  char data [] = "dafdfdasfds";

  for(i = 0;i < 1000;i++){

    Java_com_example(data);

  }

}

例子2代碼會導致local reference table overflow

大家寫jni的代碼時要防止jni層的內存泄露,要注意用本地語言的方式清除本地語言獲得的內存,

也要注意local reference和global reference的使用。

 

當然jni官文文檔中沒有告訴我們jni層實現的細節,只告訴我們如何規範的編寫jni代碼,這當然是正確的做法。

對於使用者來說只需要關注的他的使用不需要關注實現細節,這樣就保證了可擴展性。

 

所以對於不同的對local reference的實現可能結果不一樣,就有可能不出現上面local reference table overflow的錯誤了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章