利用MAT对app简单进行一次内存泄漏分析

1.什么情况下最容易内存泄漏

制作一个内存泄漏的案例. 
MainActivity
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void openOOM(View v){
        Intent intent = new Intent(this, OOMActivity.class);
        startActivity(intent);
    }
}

OOMActivity
public class OOMActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_oom);
        LoadPicThread loadPicThread = new LoadPicThread();
        loadPicThread.start();
    }

    private class LoadPicThread extends Thread {
        @Override
        public void run() {
            super.run();
            while(true) {
                    try {
                            Thread.sleep(1000*60*10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                }
        }
    }
}

重复多次打开这个activity, 后果可想而知, 为什么会内存泄漏? 看其他文章.

2. 开始调查内存泄漏

(1)打开ddms工具, 进行一系类操作

第1步 ,   选中我们要查看的应用,点击Update Heap按钮,这时候DDMS就会通知应用准备收集内存信息,
第2步,  选择Heap标签,heap标签页能够展示出内存的所有信息。
第3步,   点击Cause GC
第4步,   观察Total Size的变化, 多次GC发现totalsize 持续增加. 正常情况下, 应该是在一个范围内波动. 所以有内存泄漏了.
第5步,   导出内存快照, hprof文件

(2)利用MAT进行分析
ddms导出的hprof文件不能被MAT识别, 需要转换一下. 打开到文件目录, 然后转化为mat能识别的hprof


之后利用MAT打开转换之后的文件


先介绍两个名词第一个Shallow Heap,表示对象本身的内存大小,包括对象的头以及成员变量等,第二个Retained Heap表示:一个对象本身以及它持有的所有对象的内存总和,也就是GC时,回收一个对象所释放的所有内存空间。从这张图中可以看到,Retained Heap最大的时Resources对象,但是Resource是System Class对象,也就是系统管理的对象,也不会是引起我们内存泄漏的原因,我们不用去分析它。

第二大的就是Bitmap对象。从前面的介绍我们已经知道,如果一个对象能被GC Roots直接或者间接引用,它就不能被回收,那我们就来看一下BitmapGC Roots的引用路径,看Bitmap时被哪个对象持有的。选中Bitmap,右键选择,Path To GC Roots,再选择execlude weak references,因为弱引用是不能阻止垃圾回收的,所以我们直接排除弱引用。

(2-1)DominatorTree视图

Dominator Tree能列出内存中所有对象,以及他们占用内存的大小。


最后被持有是SystemClass. 仍然找不出什么端倪.
(2-2)DominatorTree视图看不出什么端倪, 那试试Histogram视图
借助MAT的Histogram功能,它能列出内存中的所有类,以及每个类的实例个数。


看这个对象多可疑啊.怎么有这么多实例

终于找到了问题的根源了.MAT提供了正则搜索的功能,可以根据类名搜索,我们这里搜索得到的结果是15个Activity对象,所以进一步验证成功。就是因为我们创建的那个Thread持有着Acitivy的对象,导致关闭之后Activiy不能回收。

猜你喜欢

转载自blog.csdn.net/liyang_nash/article/details/79817379