一、Android内存分析基础
1、查看进程分配的最大内存
每个App进程可以分配到的最大内存是有限的,当然不同型号的手机,为每个App进程分配的最大内存有可能也不一样
可以通过以下命令查看APP给每个进程分配的最大堆内存:
adb shell getprop | grep dalvik.vm.heapsize
2、查看进程的内存使用情况
adb shell dumpsys meminfo [包名]
Pss: 该进程独占的内存+与其他进程共享的内存(按比例分配,比如与其他3个进程共享9K内存,则这部分为3K)
Privete Dirty:该进程独享内存
Heap Size:分配的内存
Heap Alloc:已使用的内存
Heap Free:空闲内存
二、使用Android Profiler查看内存
在AndroidStudio中通过 View -> Tool Windows -> Android Profiler 可以找到Android Profiler窗口。
打开Android Profiler窗口,如下所示:
· 进程占用总内存
· javaHeap:这部分内存大小是有限制的,溢出则会OOM,这部分内存也是我们分析优化的重点
· NativeHeap:native层的 so 中调用malloc或new创建的内存,对于单个进程来说大小没有限制,所以可以利用在native层分配内存来缓解javaHeap的压力(比如2.3.3之前Android Bitmap的内存分配就是在native层,之后移到javaHeap, 8.0又回到native)
· Graphics:这部分一般游戏app中用的较多,OpenGL和SurfaceFlinger相关的内存,若没有直接调用到OpenGL,则一般不会涉及到这块内存
· Stack:java虚拟机栈内存
· Code:代码,主要是dex以及so等占用的内存
· Others:就是others
所以我们可以看到事实上我们可以优化的点有:JavaHeap、NativeHeap、Stack、Code所占用的内存
三、 使用Android Studio和MAT进行内存泄露分析
1、Android的内存泄漏分析工具常用有Android Studio和基于eclipse的MAT(Memory Analyzer Tool)。通过两者配合,可以发挥出奇妙的效果。Android Studio能够快速定位内存泄漏的Activity,MAT能根据已知的Activity快速找出内存泄漏的根源。
第一步:强制GC,生成Java Heap文件
我们都知道Java有一个非常强大的垃圾回收机制,会帮我回收无引用的对象,这些无引用的对象不在我们内存泄漏分析的范畴,Android Studio有一个Android Monitors帮助我们进行强制GC,获取Java Heap文件。
强制GC:点击Force Garbage Collection(1)按钮,建议点击后等待几秒后再次点击,尝试多次,让GC更加充分。然后点击Dump Java Heap(2)按钮,然后等到一段时间,便会生成.hrof文件。
生成的Java Heap文件会在新建窗口打开。我们可以通过点击把.hprof文件保存到本地。
第二步:分析内存泄漏的Activity
然后可以把上一次生成的.hprof拖拽到Android Studio中,然后点击右边的一个Analyzer Tasks 按钮,如下所示:
找到可能产生泄露的Activity,点击绿色按钮,最后便可以查看泄露的引用链,如下所示:
个人感觉AndroidStudio查看泄露不是很准确,如果想准确知道泄露的引用链的话,可以结合MAT来分析。
第三步:转换成标准的hprof文件
前提:安装elipse和MAT(https://blog.csdn.net/u010335298/article/details/52233689)
1、打开cmd窗口,然后进入到Android sdk tools 目录中
2、执行hprof-conv befor.hprof after.hprof 命令
3、把标准的hprof文件拖入到elipse中
第四步:查看内存泄露的引用链
右击搜索出来的类名,选择Merge Shortest Paths to GC Roots的exclude all phantom/weak/soft etc. references,来到这一步,就可以看到内存泄漏的原因,我们就需要根据内存泄漏的信息集合我们的代码去分析原因。
代码如下
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进行内存泄露检测
只要集成程序自动帮忙抓取内存泄露,gitHub地址如下: