1、問題背景
由於定位問題需要,將 cronet 庫中 quic 部分的 LOG_LEVEL 爲 -3 級別的日誌一併通過回調函數輸出了,
但導致了 cronet 庫的崩潰,崩潰的直接原因是輸出日誌過多,導致了 jni 層的局部引用表溢出。
那麼肯定是代碼中使用局部引用的次數過多、過頻繁,並且未及時釋放這些局部引用,從而導致了崩潰。
2、問題定位、解決
-
2.1 問題分析
首先需要了解什麼樣的局部引用會導致這樣的問題,以及這些局部引用如何釋放,以及合適的釋放時間點
局部引用包括 FindClass 返回的對象引用,NewXXX 等方法返回的對象,如果通過 return 返回到 Java 層,
或者通過 CallVoidMethod 等方法傳遞到了 Java 層,則在 C++ 層不需要釋放它們,否則需要手動釋放這些對象, -
2.2 問題代碼定位
代碼中,下面這段代碼中的 callback_class 變量並未被後續使用,且爲通過某個方法傳遞到 Java 層,
且未手動釋放,可能造成了對象局部引用溢出。
jclass callback_class = handleInstance->getCallbackClass();
if (callback_class == NULL || callback_class == 0) {
LOGW("From cache class Unable to find");
}
該部分代碼未在後續代碼中使用,因此可以直接刪除,重新編譯 cronet 提交測試發現仍然崩潰,
繼續分析代碼,有兩處 new 了 string 對象:
jstring logString = env->NewStringUTF(str.c_str());
env->CallVoidMethod(callback.obj(), callback_fun, severity, fileString,
jMsgStart, logString);
後續並未刪除 logString,因此可以增加代碼,刪除這些引用:
env->DeleteLocalRef(logString);
重新打包測試,崩潰未再出現。
參考鏈接
JNI error : Local reference table overflow 512 entries
JNI內存泄露處理方法彙總