一、app內存泄露調試
1、通過adb shell dumpsys meminfo packageName來查看內存使用狀況
在沒有打開應用的情況下,該命令返回的數據是這樣的:
2、打開這個應用的MainActivity,再通過命令查看:
可以看到打印出來很多的信息,而對於我們查看Activity內存泄漏來說,只需要關注Activities和Views兩個信息即可,在應用中存在的Activity對象有一個,存在的View對象有13個。
3、這時候我們退出這個Activity,在用命令查看一下:
可以看到,Activity對象和View對象都在極短的時間內被回收掉了。再次打開,退出,多次嘗試,發現情況都是一樣的。我們可以通過這種方式來簡單判斷一個Activity是否存在內存泄漏,最后是否能夠被回收。
4、再運行剛才的泄漏的例子,用命令查看一下:
當我們連續打開退出同一個頁面,然后使用命令查看時,發現Activity存在13個,而View則存在了234個,而且沒有很快被回收,依次判斷應該是存在內存泄漏了。
等待10多秒,再次查看,發現Activity和View的數量都變成了0。
上面的例子,是Handler臨時性內存泄漏,只要Handler post的代碼塊執行完畢,被引用的Activity就能夠釋放。
除了臨時性內存泄漏,還有危害更大,直到程序結束才能被釋放的內存泄漏。
5、
android程序內存被分為2部分:native和dalvik,對於內存的限制是 native+dalvik 不能超過最大限制。
android程序內存一般限制在16M,也有24M的。
Native Heap Size 約等於Native Heap Alloc + Native Heap Free
Native Heap:Native代碼分配的內存,虛擬機和Android框架分配內存。
Dalvik Heap:Java對象分配的占據內存
Dalvik Other:類數據結構和索引占據內存
Stack:棧內存
Ashmem:不以dalvik- 開頭的內存區域,匿名共享內存用來提供共享內存通過分配一個多個進程可以共享的帶名稱的內存塊。匿名共享內存(Anonymous Shared Memory-Ashmem。Android匿名共享內存是基於Linux共享內存的,都是在tmpfs文件系統上新建文件,並將其映射到不同的進程空間,從而達到共享內存的目的,只是,Android在Linux的基礎上進行了改造,並借助Binder+fd文件描述符實現了共享內存的傳遞。
Other dev:內部driver占用的內存
.so mmap C庫代碼占用的內存
.jar mmap java文件代碼占用的內存
.apk mmap apk代碼占用的內存
.ttf mmap ttf文件代碼占用的內存
.dex mmap dex文件代碼占用內存。類函數的代碼和常量占用的內存,dex mmap是映射classex.dex文件,Dalvik虛擬機從dex文件加載類信息和字符串常量等。Dex文件有索引區和Data區
Other mmap 其它文件占用的內存
6、app開發減少內存方法:
盡量不要在循環中創建太多的臨時變量
盡量把大型的循環拆散,分段或按需執行
引入SDK庫和調用新的系統API時,主要不常用功能的消耗,可考慮多進程方案,影響內存放入臨時進程執行
調整Dex文件的順序可以優化空間
二、其他命令
1、adb shell procrank
手機中的sh是經過精簡過的。有些手機可能沒有 procrank 命令。能夠使用genymotion模擬器。或是自己安裝procrank命令。使用procrank時,命令行的輸出入下圖:
能夠看到,在linux下表示內存的耗用情況有四種不同的表現形式:
VSS - Virtual Set Size 虛擬耗用內存(包括共享庫占用的內存)
RSS - Resident Set Size 實際使用物理內存(包括共享庫占用的內存)
PSS - Proportional Set Size 實際使用的物理內存(比例分配共享庫占用的內存)
USS - Unique Set Size 進程獨自占用的物理內存(不包括共享庫占用的內存)
VSS:VSS表示一個進程可訪問的所有內存地址空間的大小。
這個大小包含了進程已經申請但尚未使用的內存空間。在實際中非常少用這樣的方式來表示進程占用內存的情況,用它來表示單個進程的內存使用情況是不准確的。
RSS:表示一個進程在RAM中實際使用的空間地址大小。包含了所有共享庫占用的內存。這樣的表示進程占用內存的情況也是不准確的。
PSS:表示一個進程在RAM中實際使用的空間地址大小,它按比例包括了共享庫占用的內存。假如有3個進程使用同一個共享庫,那么每一個進程的PSS就包括了1/3大小的共享庫內存。
這樣的方式表示進程的內存使用情況較准確。但當僅僅有一個進程使用共享庫時,其情況和RSS一模一樣。
USS:表示一個進程本身占用的內存空間大小,不包括其他不論什么成分,這是表示進程內存大小的最好方式!
能夠看到:VSS>=RSS>=PSS>=USS
2、adb shell后 echo 3>/proc/sys/vm/drop_caches (清除一下系統cache)
3、adb logcat -v
time 加上時間戳
4、采集某個應用的內存數據
這個實踐和上面的腳本類似,只是命令不一樣我另外單獨列出來,因為這個有時候很有用。
比如,我們要采集com.tianxia.test的內存使用情況,分析它是不是會內存泄露,腳步類似:
# !/system/bin/sh #這個腳步比較粗糙,是這么個意思 file=/sdcard/cpu/mem_info.log rm $file until [ 1 -gt 10000 ] do echo -e "\n\n\n\n\n---------------">>$file date >> $file dumpsys meminfo com.tianxia.test >> $file sleep 3 done
5、查看單個應用程序最大內存限制
adb shell getprop|grep heapgrowthlimit
設備不一樣 最大內存限制也可能不一樣