内存检测的思路
静态检测 -> 工具检测 -> 修复
相关知识点
JAVA 的内存回收机制,内存空间中垃圾回收的工作由垃圾回收器 (Garbage Collector,GC) 完成的,它的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,如果对象正在被引用,那么称其为存活对象,反之,如果对象不再被引用,则为垃圾对象,可以回收其占据的空间,用于再分配。
在垃圾回收机制中有一组元素被称为根元素集合,它们是一组被虚拟机直接引用的对象,比如,正在运行的线程对象,系统调用栈里面的对象以及被 system class loader 所加载的那些对象。堆空间中的每个对象都是由一个根元素为起点被层层调用的。因此,一个对象还被某一个存活的根元素所引用,就会被认为是存活对象,不能被回收,进行内存释放。因此,我们可以通过分析一个对象到根元素的引用路径来分析为什么该对象不能被顺利回收。如果说一个对象已经不被任何程序逻辑所需要但是还存在被根元素引用的情况,我们可以说这里存在内存泄露。Memory churn:内存抖动是因为在短时间内大量的对象被创建又马上被释放。瞬间产生大量的对 象会严重占用Young Generation的内存区域,当达到阀值,剩余空间不够的时候,会触发GC从而导致刚产生的对象又很快被回收。解决内存抖动可以在Memory Monitor里面查看到短时间内发生内存涨跌次数,找到引发内存抖动的操作对应的代码,然后就行修改。也可以通过Allocation Tracker来查看在短时间内,同一个栈中不断进出的相同对象。这是内存抖动的典型信号之一。比如for循环场景,自定义View的onDraw场景,避免在onDraw()场景创建对象,如无法避免可以使用对象池模型。
Memory Leaks:内存泄露表示不再用到的对象因为被错误引用而无法进行回收,比如Activity destroy之后,仍有线程持有Activity对象,则Activity就不会被回收。内存泄露会导致Memory Generation中剩余的Heap size会越来越小,进而就可能导致频繁的GC,而jvm会因为执行gc而停止应用程序的执行,页面变卡,引起性能问题。
造成OutOfMemoryError原因一般有2种:
内存泄露,对象已经死了,无法通过垃圾收集器进行自动回收,通过找出泄露的代码位置和原因,才好确定解决方案;
内存溢出,内存中的对象都还必须存活着,这说明Java堆分配空间不足,检查堆设置大小(-Xmx与-Xms),检查代码是否存在对象生命周期太长、持有状态时间过长的情况。
工具篇
系统工具篇
Android Monitor
- Memory
- CPU
- Network
- GPU
MAT:Memory Analyzer Tool
JAVA 堆转储文件分析工具,可以帮助你发现内存漏洞和减少内存消耗
分析的思路可以参见使用mat工具分析内存占用
TraceView
- 代码调用:在观测代码的开始和结束处分别调用(分析的颗粒度更小)
Debug.startMethodTracing("tracefilename");
Debug.stopMethodTracing();
运行你的代码一段时间并退出会在sd卡根目录生成tracefilename.trace这个log文件,记录这段时间内的运行信息。可以参见TraceView如何使用
- DDMS:Dalvik Debug Monitor Server 监控整个进程的使用情况
启动位置:Android Studio/Tools/Android Device Monitor
Heap Viewer:查看当前内存快照,便于对比分析哪些对象有可能发生了泄漏。可以观察data object的Totalsize字段,当我们一直操作应用,Totalsize一直在增加,并且随着GC操作,该值没有明显的下降,则我们可以大致的判断是引起内存泄露的操作范围。
Allocation Tracker:追踪内存对象的来源
第三方工具篇
Godeyes
专注于静态代码扫描,提供针对常见问题的代码检测,生成报告,并给出出现问题的地方及推荐解决方案。
LeakCanary
LeakCanary是一个检测内存泄露的开源类库。你可以在 debug包种轻松检测内存泄露。
WeakHander
一种对Handler的若引用封装
GT
腾讯出品的,直接运行在手机上的“集成调测环境”(IDTE, Integrated Debug Environment)。