天天看點

Cocos中調用JNI,報錯local reference table overflow (max=512)

最近公司的遊戲項目中出現了一個奇怪的bug。安卓端當旁觀玩家過多,比如達到150人的時候,直接崩潰。

出現這個bug的時候,我也很崩潰。仔細看了一下log,提示

`local reference table overflow (max=512)`
           

百度一下,說是Android JNI局部引用表溢出。

根據操作步驟,定位到了lua代碼中的引起報錯的代碼塊。仔細檢視了代碼,發現是lua調用android端方法,擷取旁觀者的昵稱與備注。因為lua調用android端方法是通過

luaj.callStaticMethod

去調用,再捋一下實作方法,發現是在lua-bindings的CCC代碼中去實作。好,按照網上的說法,是因為循環建立新的字元串并傳回指向這個字元串的局部引用,這樣造成局部引用表被填滿。而Android中局部引用表預設最大容量是512個。

這樣一來,思路很清晰了,根據網上教程,字元串使用完成之後,調用DeleteLocalRef删除局部引用。一看到這很激動,馬上就能解決問題了。然後傳回到實際C++代碼中一看,發現并沒有網上說的建立新的字元串的情況,死馬當活馬醫醫,依葫蘆畫瓢一下。改好C++之後,重新編譯so檔案,測試一下,然并卵,該崩潰照樣崩潰。

後來再仔細看了一下lua代碼,發現代碼中根據旁觀者人數集合長度,循環的在調用JNI。轉變思路一想,我把集合直接傳給android端,android端查找好昵稱之後,再傳回給lua,這樣JNI隻需要調用一次了。按照思路修改了之後,果然可以了。

其實還有更好的解決方案:本局遊戲中進入了玩家之後,服務端發送進入通知,帶上所有玩家的資訊,緩存好所有玩家資訊,這樣需要顯示時,隻需要查找緩存,不需要從app端調用方法查詢。這樣省時省力省記憶體。

修改bug主要是思路上要清晰。雖然看起來我這寫的很簡單,但是其中走了很多彎路。定位問題不夠準确,導緻浪費了很多時間。以後要注意