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