android中產生內存泄漏的原因很多,比如廣播未注銷,handler使用不當,Activity的context被單例引用等。規范編碼可以避免很多內存泄漏問題,本文對引起內存泄漏的原因不做深入討論,只記錄如何使用android studio和mat工具分析內存泄漏,解決問題。
android studio提供了profiler幫助開發者監測內存。打開AS,跑起項目可以看到這樣的界面
點擊Android Profiler打開性能分析界面
注意選擇你要分析的設備和進程。這里除了內存分析,還可以進行CPU和網絡的分析檢測。點擊圖中藍色的內存區域,進入內存分析界面
圖中顯示的就是當前進程的內存使用情況,點擊左上角的垃圾桶按鈕可以觸發一次GC,如果內存沒有泄露,理想狀態下,界面反復跳轉之后GC內存應該可以回到初始狀態(允許小幅度上升),如果發現跳轉到某個頁面再回來發現GC無法回收內存,反復跳轉后內存持續上升且無法回收,則說明該頁面肯定發生了內存泄漏。
操作你的app,跳轉到某個要測試的界面然后返回,連續操作幾次后返回初始界面,手動進行一次垃圾回收(圖中垃圾桶按鈕),點擊上圖的箭頭按鈕記錄一段內存信息,點擊后幾秒鐘會自動完成記錄,完成后出現以下界面?
這就是當前app中所有代碼占用內存的情況,可以選擇Arrayge by class選擇查看方式,一般選擇包名查看方式可以方便找到自己的代碼,查看代碼中的對象實例個數,要想更準確的分析內存情況就要使用其他工具協助——mat(Memory Analyzer)。點擊上圖左邊按鈕導出內存信息以備mat分析使用,直接導出的hprof文件在eclipse的mat工具中是不能直接打開的,需要轉換一下,轉換過程也很簡單,使用SDK自帶的hprof工具即可:cmd定位到你的SDK路徑下的platform-tools文件夾,使用命令 hprof-conv D:\memory\a1.hprof D:\memory\b1.hprof 轉換,D:\memory\a1.hprof是剛才保存的源文件路徑,D:\memory\b1是要保存的轉換后的文件路徑。mat工具官網下載地址https://www.eclipse.org/mat/downloads.php百度云盤地址鏈接:https://pan.baidu.com/s/1sa2mZ1xNnWEeq0BidXIerw提取碼:t8ns? ? 下載解壓后打開一個Eclipse形狀的MemoryAnalyzer.exe。界面打開后是這樣的
點擊file->open heap dump導入剛才轉換后的文件
點擊打開Histogram視圖查看類詳情
輸入你認為可能內存泄漏的類名可以看到,這個Fragment有兩個實例,但是不能就確定是發生了內存泄漏,因為可能包含若引用和軟引用的對象實例,而這些是可以被回收的,要想查看真正無法被回收的實例個數:右鍵選擇去掉弱、軟、虛等引用后的實例
打開后的視圖就是真正的內存泄漏的情況
可以看到這個對象確實存在有兩個實例無法被銷毀(我測試的時候跳轉了兩次這個界面)這就說明我們的代碼確實發生了內存泄露,mat工具中雖然無法明確告訴我們哪一行代碼發生了內存泄露,卻可以告訴我們是什么引起的,從圖中可以看到是Rxbus引起的,查看該類中的代碼發現Rxbus使用后沒有注銷,導致全局的消息隊列中一直持有該fragment實例的引用,GC做回收時,會根據回收算法分析該對象的引用鏈,回收引用不可達的對象,如果不再使用的對象仍然存在引用鏈中則無法被回收,這就是發生了內存泄漏的對象。添加注銷代碼重新分析后發現剛才發生泄漏的fragment強引用實例變成了零。這樣就解決了這個內存泄漏問題。關于mat的其他使用方式,感興趣的可以去看官網介紹或者其他介紹文章。
這只是一個簡單的內存泄漏例子,實際開發中的內存泄露往往要復雜的多,但是根據這樣的分析過程,可以定位大部分內存泄漏問題。需要注意的是,良好的編碼習慣是避免內存泄漏最好的方式。