最近在做項目的過程中發(fā)現(xiàn)一個比較詭異的現(xiàn)象:生產環(huán)境中谤祖,在Android 4.x系統(tǒng)上Release版本上比較頻繁的的出現(xiàn)ANR, 而Debug版本沒有出現(xiàn)些楣;同時掂碱,在Android 6.x系統(tǒng)上也有個別手機會出現(xiàn)此問題躏敢。根據(jù)問題發(fā)生的場景商佛,進行了反復的測試喉钢,發(fā)現(xiàn)ANR的現(xiàn)象基本發(fā)生在固定兩個頁面。
采取了兩個思路:
1良姆、查看log與trace文件肠虽,Review兩個頁面的代碼,看是否有出現(xiàn)耗時的操作
2玛追、簡化代碼税课,去除其他模塊的影響
措施1: Review代碼及查看log與trace文件
-- 查看簡化相關模塊的代碼,沒有發(fā)現(xiàn)特別耗時的操作
-- 在出現(xiàn)ANR的地方查看日志痊剖,沒有發(fā)現(xiàn)有價值的信息
-- 獲取到trace文件韩玩,查看文件中是否存在死鎖、消息廣播阻塞及線程的互相
等待陆馁,搜索關鍵字找颓,查看對應的tid與pid,沒有發(fā)現(xiàn)異常叮贩。
花了2-3天時間的叮雳,特別是對log文件的觀察與學習trace文件的理解想暗,還是挺花時間的,措施1基本沒有什么發(fā)現(xiàn)帘不。
措施2: 重寫與簡化代碼
-- 由于項目模塊較多说莫,并且模塊間有一定的耦合性,簡單的簡化代碼可能達不到預想的效果寞焙,因為采取重新創(chuàng)建工程的方式储狭,移植并簡化代碼,保證出現(xiàn)問題的固定兩個頁面可用即可捣郊。
-- 移植完畢后辽狈,反復測試,發(fā)現(xiàn)問題仍然存在呛牲。
-- 繼續(xù)簡化代碼刮萌,去掉應用中的一個自定義組件,加密鍵盤娘扩,發(fā)現(xiàn)問題消失
-- 懷疑是否與鍵盤Java層代碼的內存泄漏有關着茸,查看管理部分的代碼,并且結合集成LeakCandary內存泄漏檢測工具琐旁,確實存在單例模式使用不當造成的內存泄漏涮阔,解決內存泄漏問題,問題仍然存在灰殴,因此判定不是Java層內存泄漏引起的敬特。
-- 既然與Java層內存泄漏沒有關系,懷疑的重點就放在了底層JNI的加解密上牺陶,由于底層涉及到3次對密碼進行加解密伟阔,猜測是否與加解密函數(shù)有關系,注釋調加解密加解密部分代碼掰伸,發(fā)現(xiàn)問題消失减俏,因此確定問題可能與加解密部分代碼有關系
-- 通過多次注釋與測試,問題代碼縮小到登錄密碼加密部分的代碼碱工,經過不斷的修改測試及代碼Review娃承,發(fā)現(xiàn)了一個嚴重的內存越界問題:malloc動態(tài)分配的內存大小為srcLen,但是在后續(xù)的使用過程有一個函數(shù)是將Hex字節(jié)數(shù)組轉化為字符串怕篷,在最后一個字符串賦值時历筝,char* 的數(shù)組下標引用為srcLen, 并賦值為\0結束符。
明顯此處訪問內存是出現(xiàn)了越界廊谓,總共分配了srcLen大小的內存梳猪,而在使用時卻訪問到了strLen +1長度的內存,而這個后果是不可預知的,修正后再測試春弥,問題消失呛哟。
這個過程費時費力,前后花了差不多一周時間匿沛,還好總算是在正確的方向上扫责。問題解決后,仍然帶有一些疑問:
1逃呼、為什么問題在Debug版本反復測試沒有出現(xiàn)鳖孤,是不是因為在Release模式下內存的分配與檢查更加的嚴格,而Debug模式下抡笼,內存的管理與Release不一樣苏揣,可能分配的內存更加的充足?這樣即使內存越界了推姻,如果越界的內存是空閑內存平匈,仍然不會觸發(fā)整個應用的ANR, 為了進一步找原因,仔細查看了內存泄漏藏古、內存越界增炭、內存溢出的易發(fā)場景及C程序在運行是的內存分配,最后也沒有找到原因校翔。
2弟跑、為什么在Android 4.x的系統(tǒng)上頻繁復現(xiàn)灾前,而高版本的系統(tǒng)上出現(xiàn)概率不高防症?這個問題的也許可以這樣解釋:1、內存越界的問題本身就非常隱蔽哎甲,并且造成的后果頁不可知蔫敲,如果搞好越界的內存是空閑內存,問題可能就不會理解發(fā)生直到越界的內存被另外的程序分配了內存才會真正觸發(fā)問題的產生 2炭玫、高版本的使用ART運行時編譯器及Android底層內存管理更加優(yōu)化
3奈嘿、為什么內存越界會導致應用程序的ANR? 可能是因為內存越界導致的后果具有不確定性,當問題越界時引用其他代碼分配的內存快吞加,兩段程序對內存資源的競爭導致應用程序的超時出現(xiàn)了ANR裙犹,這也只是猜測。
帶著這些疑問衔憨,又把C程序中關于內存管理的基礎知識復寫了一遍叶圃,具體見鏈接:
1、C語言內存管理一本道來 http://www.reibang.com/p/502a1919e189
2践图、42_內存操作經典問題分析二 http://www.reibang.com/p/d998176f80f0
總結:
當遇到類似ANR的問題時掺冠,可以考慮使用以下的這些方法輔助定位:
1、根據(jù)業(yè)務場景查看log及trace文件
如何查看log
如何查看trace文件:是否有死鎖码党、是否有明顯的應用程序類
2德崭、推翻重寫或簡化代碼
3斥黑、集成第三方工具LeakCandary
當真的是沒有什么頭緒時,要跳出ANR的局限思維眉厨,猜測有沒有可能是內存問題了锌奴。