首先說一下出現(xiàn)這個問題的背景抡笼,通過Android的Camera采集視頻信息然后通過JNI來調(diào)用C來軟編碼,但是發(fā)現(xiàn)有的手機(jī)再錄制時間超過5分鐘后就會出現(xiàn)異常崩潰档痪!通過抓log發(fā)現(xiàn)是:“JNI pinned array reference table (0x5d4440a8) dump; ReferenceTable overflow (max=1024)”引起的奔潰捐下!
其中 ReferenceTable overflow (max=1024) 這句log是最關(guān)鍵的,它指出是由于引用計數(shù)器溢出造成的崩潰雁比,看到這里后我排查了JNI代碼,果然是JNI代碼處理問題,因?yàn)槲颐看握{(diào)用JNI方法時都會調(diào)用GetByteArrayElements來接受byte數(shù)組撤嫩,但是卻一直沒有釋放
uint8_t *inputBuffer = (uint8_t *) env->GetByteArrayElements(inputBuffer_, 0);
解決方案就是JNI方法中用完一行一定記得要釋放,調(diào)用: env->ReleaseByteArrayElements(jbyteArray array, jbyte elems,
jint mode)*
總結(jié)一下JNI中經(jīng)常遇到的問題:
- 忘記釋放引用或釋放內(nèi)存
凡是用到New的方法都需要手動進(jìn)行釋放(如:env->NewByteArray)偎捎,調(diào)用: env->DeleteLocalRef方法進(jìn)行釋放,
還有調(diào)用GetByteArrayELement方法也要手動釋放,調(diào)用:env->ReleaseTypeElements方法進(jìn)行釋放序攘,如果只是取bytearray中的byte可以使用GetByteArrayRegion*方法來獲取
2.發(fā)生Reference Table overflow (max=1024) 或 Reference Table overflow (max=512)之類的異常
如果發(fā)生類似的異常茴她,就去排查JNI的代碼,肯定有未釋放的引用(global reference两踏、local reference)
3.多線程的問題
第一種情況:在多線程使用JNIEnv對象败京,需要AttachCurrentThread將env掛到當(dāng)前線程,否則無法使用env
第二種情況:在多線程中調(diào)用java方法梦染,需要保存jobject對象,這時需要對jobject對象做全局引用(NewGlobalRef*)朴皆,否則會失效
4.在JNI層獲取jbytearray長度
不應(yīng)該在JNI層獲取jbytearray長度帕识,應(yīng)該在java層獲取byte數(shù)組長度,然后再傳給JNI層