最近的一次事件讓我對 Android 開發中內存泄漏重視起來,平時只忙着開發新的功能,往往會忽略掉內存,cpu 等方面的使用情況,然而遇到 內存泄露或者ANR 問題就要徹底解決,由於Android設備規格不一,好一些的設備上不會出現問題,在一些低端的設備上就會出現各種問題,所以平時也要注意內存泄漏和 cpu 使用問題.
同步發不在簡書Android 內存泄漏工具使用分析
內存泄漏(memory leak)
A memory leak is a particular type of unintentional memory consumption by a computer program where the program fails to release memory when no longer needed. This condition is normally the result of a bug in a program that prevents it from freeing up memory that it no longer needs.This term has the potential to be confusing, since memory is not physically lost from the computer. Rather, memory is allocated to a program, and that program subsequently loses the ability to access it due to program logic flaws.
看不懂 pass。。。知道有這麼回事就可以了
初步判斷
現象判斷
從現象入手,如果肉眼能看出頁面卡頓,那肯定是有問題的,首先,嘗試連續多次打開應用,觀察界面卡頓,動畫現象,並截取 log,觀察 log 中的 GC 輸出
日誌,頻繁打印GC日誌,說明系統頻繁觸發GC來釋放內存,初步推斷可能存在內存泄漏,具體使用 DDMS HEAP 工具分析,以下有介紹
內存命令分析
前期可以通過一些 ADB 命令來簡單查看下內存相關信息,做初步判斷,有一次在項目中發現,開啓/關閉某個模塊,觀察內存狀態,竟然差了4M,果斷修復。
查看內存系統信息
adb shell cat proc/meminfo
➜ ~ adb shell cat proc/meminfo
MemTotal: 2052484 kB
MemFree: 1450748 kB
Buffers: 23212 kB
Cached: 342548 kB
SwapCached: 0 kB
Active: 338056 kB
Inactive: 203652 kB
Active(anon): 175960 kB
Inactive(anon): 6912 kB
Active(file): 162096 kB
Inactive(file): 196740 kB
..
查看某一應用佔用內存
adb shell dumpsys meminfo + packageName
e.g: adb shell dumpsys meminfo com.dangbeimarket
➜ ~ adb shell dumpsys meminfo com.whiskeyfei.tab
Applications Memory Usage (kB):
Uptime: 16199425 Realtime: 16199425
** MEMINFO in pid 14522 [com.whiskeyfei.tab] **
Pss Private Private Swapped Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 3474 3356 0 0 15475 15475 13196
Dalvik Heap 2861 2788 0 0 3156 2561 595
Dalvik Other 340 328 0 0
Stack 104 104 0 0
Other dev 5 0 4 0
.so mmap 1162 144 48 0
.apk mmap 220 0 16 0
.ttf mmap 126 0 16 0
.dex mmap 2648 0 2644 0
code mmap 1220 0 88 0
image mmap 1051 508 8 0
Other mmap 23 4 0 0
Unknown 89 88 0 0
TOTAL 13323 7320 2824 0 18631 18036 13791
名詞解釋
- Native Heap: C++層內存分配。
- Dalvik Heap: Java層內存分配。
- Ashmem : 匿名共享內存。
- Stack: 棧區分配的內存。
- so mmap: C庫代碼佔用。
- jar mmap : Java文件佔用。
- apk mmap: apk代碼佔用。
- ttf mmap: ttf文件佔用。
- dex mmap: dex文件代碼佔用的內存。
- Other mmap: 其他文件佔用的內存
我們要關注 Dalvik Heap 和 Native Heap 佔用內存,在使用應用過程中實時查看內存信息狀態,來初步判斷是否內存使用不當。
DDMS HEAP 工具
Android DDMS 內存監測工具 Heap,可以檢測一個進程的內存變化,根據這個數值變化可以測試應用是否存在泄漏。
用過debug肯定會用 Heap 了,連接設備啓動 app,點 debug 右邊的按鈕即可(Update Heap 鼠標放上去能看到)
DDMS 調試
開始GC,然後就操作 app 觀察,Heap視圖中部有一個data object,即數據對象,也就是我們的程序中對象
正常情況下 Total Size 值都會穩定在一個範圍內,反之如果則 data object 的 Total Size 值在每次GC後不會有明顯的回落
隨着操作次數的增多 Total Size 的值會越來越大,就證明可能存在內存泄漏,然後通過其他工具來找出泄漏的地方;
MAT( Memory Analyzer Tool )
定位問題
通過 MAT 分析分析內存中佔用比較大的對象
MAT 是一個內存分析工具,在使用 DEAP 初步判斷頁面存在內存泄露後,使用 MAT 具體分析出哪寫對象沒有釋放,導致了內存沒有釋放,關於MAT工具安裝,請自行 Google,操作 app,例如:進入某個頁面,退出,點擊 Dump Hprof file 按鈕,等一會會打開MAT視圖,沒有安裝會生成一個文件;
先觀察“Leak suspects”,找出比較大的問題,通過 Dominator Tree 來查看 heap 中比較大的對象,也可以通過 Histogram 查找引用鏈;
Histogram 顯示內存中每個對象的數量大小等信息,可以通過關鍵字來過濾
例如:搜索 com.main.*;這樣就能查找出這些包下面類引用情況,自行右鍵獲得信息,通過提示找出有問題的類或對象,這樣就可以找出內存佔用多或者泄露的問題了;
本例子中查看 Dominator Tree -> 右鍵某一條 -> Path to GC Roots -> exclude weak references
Shallow Heap:對象本身的大小
Retained Heap:對象本身以及它持有的對象的內存總和
驗證
通過查看 Histogram 內存中的類以及實例個數
安裝地址
總結
總結了一些常用的工具,用來分析內存問題,以下是注意的步驟
- 使用 ADB 命令初步分析內存
- 操作應用觀察 HEAP update 查看當前內存變化,判斷是否存在內存泄露
- 使用 MAT 來確定哪些代碼引起了內存
如何避免
- 嚴格遵守生命週期,創建時創建,銷燬時記得回收
- Bitmip 和 Drawable 記得手動回收
- 靜態對象引用 Context,導致對象無法釋放,從而導致 Activity 無法釋放
- 自定義靜態 Handler,Runnable和 Handler 回收
- 使用 Application Context,少使用 Activity Context