通過ANR的堆棧分析,ANR的堆棧都是停在了linklist的contains()函數(shù)。通過源碼分析,系統(tǒng)提供的linklist類是通過鏈表的方式實現(xiàn)的。按說應該不會有性能問題,即使一個初級程序員來實現(xiàn),查詢幾萬條記錄的耗時最多也就是幾十毫秒。作為Android平臺的工具類,性能應該更是頂呱呱。同事通過log日志發(fā)現(xiàn),系統(tǒng)的linklist在1000條記錄情況下查詢耗時在10毫秒內(nèi)。自己的手機也沒能復現(xiàn)ANR問題。
下面進入分析階段:
由于bugly的日志上報了App所有多線程堆棧情況(這點很贊),通過堆棧分析,出問題時候,主線程和子線程都在操作linklist,并且為了線程安全,業(yè)務對所有l(wèi)inklist操作都增加了synchronized鎖。通過多個bugly上報的規(guī)律來看,子線程和主線程也都卡在了linklist的操作上。
梳理已知信息:
1、子線程和主線程都卡在了linklist上。
2、子線程和主線程同時進入了不同方法的synchronized內(nèi)。
分析:
由第一條現(xiàn)象可以嘗試的方向是linklist是否存儲的內(nèi)容特別多,由于內(nèi)容超多導致linklist操作耗時超長。(通過代碼分析,linklist內(nèi)容會定期寫文件且對內(nèi)容不排重,很有可能造成這種情況)
由第二條現(xiàn)象可以嘗試的方向是單例里持有的linklist的多個同步方法(synchronized),被子線程和主線程同時執(zhí)行,是否和單例創(chuàng)建的安全性有關。(即創(chuàng)建了兩個單例)
追問:
為什么主線程和子線程都卡在了linklist操作上,這么巧?
原因是linklist耗時超長,所以主線程和子線程同時卡在linklist操作的概率就特別大。