一、Android內(nèi)存分析基礎
1赋元、查看進程分配的最大內(nèi)存
每個App進程可以分配到的最大內(nèi)存是有限的狠毯,當然不同型號的手機,為每個App進程分配的最大內(nèi)存有可能也不一樣
可以通過以下命令查看APP給每個進程分配的最大堆內(nèi)存:
adb shell getprop | grep dalvik.vm.heapsize
2、查看進程的內(nèi)存使用情況
adb shell dumpsys meminfo [包名]
Pss: 該進程獨占的內(nèi)存+與其他進程共享的內(nèi)存(按比例分配锨亏,比如與其他3個進程共享9K內(nèi)存,則這部分為3K)
Privete Dirty:該進程獨享內(nèi)存
Heap Size:分配的內(nèi)存
Heap Alloc:已使用的內(nèi)存
Heap Free:空閑內(nèi)存
二爱葵、使用Android Profiler查看內(nèi)存
在AndroidStudio中通過 View -> Tool Windows -> Android Profiler 可以找到Android Profiler窗口雷则。
打開Android Profiler窗口猜揪,如下所示:
· 進程占用總內(nèi)存
· javaHeap:這部分內(nèi)存大小是有限制的拴念,溢出則會OOM划煮,這部分內(nèi)存也是我們分析優(yōu)化的重點
· NativeHeap:native層的 so 中調(diào)用malloc或new創(chuàng)建的內(nèi)存,對于單個進程來說大小沒有限制蟹略,所以可以利用在native層分配內(nèi)存來緩解javaHeap的壓力(比如2.3.3之前Android Bitmap的內(nèi)存分配就是在native層意敛,之后移到javaHeap, 8.0又回到native)
· Graphics:這部分一般游戲app中用的較多,OpenGL和SurfaceFlinger相關(guān)的內(nèi)存,若沒有直接調(diào)用到OpenGL,則一般不會涉及到這塊內(nèi)存
· Stack:java虛擬機棧內(nèi)存
· Code:代碼,主要是dex以及so等占用的內(nèi)存
· Others:就是others
所以我們可以看到事實上我們可以優(yōu)化的點有:JavaHeap、NativeHeap担平、Stack示绊、Code所占用的內(nèi)存
三面褐、 使用Android Studio和MAT進行內(nèi)存泄露分析
1、Android的內(nèi)存泄漏分析工具常用有Android Studio和基于eclipse的MAT(Memory Analyzer Tool)闻蛀。通過兩者配合手蝎,可以發(fā)揮出奇妙的效果邮辽。Android Studio能夠快速定位內(nèi)存泄漏的Activity,MAT能根據(jù)已知的Activity快速找出內(nèi)存泄漏的根源。
第一步:強制GC吨述,生成Java Heap文件
我們都知道Java有一個非常強大的垃圾回收機制笙僚,會幫我回收無引用的對象芳肌,這些無引用的對象不在我們內(nèi)存泄漏分析的范疇灵再,Android Studio有一個Android Monitors幫助我們進行強制GC,獲取Java Heap文件亿笤。
強制GC:點擊Force Garbage Collection(1)按鈕翎迁,建議點擊后等待幾秒后再次點擊,嘗試多次净薛,讓GC更加充分汪榔。然后點擊Dump Java Heap(2)按鈕,然后等到一段時間肃拜,便會生成.hrof文件痴腌。
生成的Java Heap文件會在新建窗口打開。我們可以通過點擊把.hprof文件保存到本地燃领。
第二步:分析內(nèi)存泄漏的Activity
然后可以把上一次生成的.hprof拖拽到Android Studio中士聪,然后點擊右邊的一個Analyzer Tasks 按鈕,如下所示:
找到可能產(chǎn)生泄露的Activity猛蔽,點擊綠色按鈕剥悟,最后便可以查看泄露的引用鏈,如下所示:
個人感覺AndroidStudio查看泄露不是很準確曼库,如果想準確知道泄露的引用鏈的話区岗,可以結(jié)合MAT來分析。
第三步:轉(zhuǎn)換成標準的hprof文件
前提:安裝elipse和MAT(https://blog.csdn.net/u010335298/article/details/52233689)
1毁枯、打開cmd窗口慈缔,然后進入到Android sdk tools 目錄中
2、執(zhí)行hprof-conv befor.hprof after.hprof 命令
3种玛、把標準的hprof文件拖入到elipse中
第四步:查看內(nèi)存泄露的引用鏈
右擊搜索出來的類名藐鹤,選擇Merge Shortest Paths to GC Roots的exclude all phantom/weak/soft etc. references,來到這一步蒂誉,就可以看到內(nèi)存泄漏的原因教藻,我們就需要根據(jù)內(nèi)存泄漏的信息集合我們的代碼去分析原因。
代碼如下
public class AppSetting {
private static AppSetting sInstance;
private static Context mContext;//傳的是Activity
private AppSetting(Context context) {
mContext = context;
}
public static AppSetting getInstance(Context context) {
if (sInstance == null) {
sInstance = new AppSetting(context);
}
return sInstance;
}
public void doSomeThing(){
}
}
四右锨、使用LeakCanary進行內(nèi)存泄露檢測
只要集成程序自動幫忙抓取內(nèi)存泄露括堤,gitHub地址如下: