Android 内存泄漏介绍及实例演示

一、内存泄漏介绍

定义:内存中存在已经没有用的对象
表现:内存抖动、可用内存逐渐减少
危害:内存不足、GC 频繁、OOM

二、内存泄漏解决实战

Memory Profiler 只能提供简单的分析,并不能确认问题,所以我们用 Memory Analyzer(简称 MAT)来确认问题。

Memory Analyzer 下载链接
转换:hprof-conv 原文件路径 转换后文件路径 (如:hprof-conv /Users/wuchao/AndroidStudioProjects/imooc/Performance/memory-leak.hprof /Users/wuchao/AndroidStudioProjects/imooc/Performance/memory-leak_trans.hprof )

下面是实例代码:

/**
 * @desciption: 模拟内存泄露的Activity
 */
public class MemoryLeakActivity extends AppCompatActivity implements CallBack {

    private AppCompatImageView mIvMemoryleak;

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

    private void initView() {
        mIvMemoryleak = (AppCompatImageView) findViewById(R.id.iv_memoryleak);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.splash);
        mIvMemoryleak.setImageBitmap(bitmap);
        CallBackManager.addCallBack(this);
    }

    @Override
    public void dpOperate() {

    }
}

public class CallBackManager {

    public static ArrayList sCallBacks = new ArrayList<>();

    public static void addCallBack(CallBack callBack) {
        sCallBacks.add(callBack);
    }

    public static void removeCallBack(CallBack callBack) {
        sCallBacks.remove(callBack);
    }

}
public interface CallBack {
    void dpOperate();
}

为了实现内存泄漏的效果,我们反复进入 MemoryLeakActivity 这个类。则 Memory Profiler 的分析图,如下图:

Android 内存泄漏介绍及实例演示_第1张图片

从图中可以看到内存呈阶梯状上升,也就是说可用内存逐渐减少,则可以断定页面出现了内存泄漏。但是 Memory Profiler 工具不能断定哪个地方有内存泄漏,这时我们需要用 Memory Analyzer 工具。

在 Memory Profiler 界面点击Dump Java heap 按钮,如下图红框中所示:

然后点击保存按钮,如下图红框中所示:

Android 内存泄漏介绍及实例演示_第2张图片

由于保存的文件不能直接使用,需要对这个保存的文件进行转换:

转换:hprof-conv 原文件路径 转换后文件路径 (如:hprof-conv /Users/wuchao/AndroidStudioProjects/imooc/Performance/memory-leak.hprof /Users/wuchao/AndroidStudioProjects/imooc/Performance/memory-leak_trans.hprof )

转换过程如下图所示:

Android 内存泄漏介绍及实例演示_第3张图片

然后由 Memory Analyzer 工具打开转换后的文件,如下图:

Android 内存泄漏介绍及实例演示_第4张图片

Histogram 菜单列出了内存中存活的所有对象,如下图:

Android 内存泄漏介绍及实例演示_第5张图片

由于 Histogram 菜单中内容较多,需要搜索匹配 MemoryLeakActivity。如下图:

从图中可以看出内存中竟然有 8 个 MemoryLeakActivity 对象。这是很不合理的。

接下来我们要找那些强引用引用了 MemoryLeakActivity 类,如下图操作流程:

Android 内存泄漏介绍及实例演示_第6张图片

with incoming references:表示查看该类被哪些类所引用

点击 with incoming references 后界面如下:

Android 内存泄漏介绍及实例演示_第7张图片

然后找到 Path TO GC Roots ,然后选择去掉所有引用(可根据情况选择其他选项),如下图所示步:

结果如下图:

Android 内存泄漏介绍及实例演示_第8张图片

从图中可以看出 MemoryLeakActivity 类被 CallBackManager 类中的 sCallBacks 属性引用。
我们进入 CallBackManager 类中

public class CallBackManager {

    public static ArrayList sCallBacks = new ArrayList<>();

    public static void addCallBack(CallBack callBack) {
        sCallBacks.add(callBack);
    }

    public static void removeCallBack(CallBack callBack) {
        sCallBacks.remove(callBack);
    }

}

sCallBacks 被 static 所修饰,它的生命周期和整个 APP 一致。

解决方案:
在 MemoryLeakActivity 类中加入以下代码即可:

    @Override
    protected void onDestroy() {
        super.onDestroy();
        CallBackManager.removeCallBack(this);
    }

在 MemoryLeakActivity 销毁时将它自己从 CallBackManager 中移除。这样我们的内存泄漏就解决完了。

总结

  • 使用 Memory Profiler 初步观察
    可用内存逐渐减少,然后断定可能有内存泄漏

  • 通过 Memory Analyzer 结合代码确认

Android 内存抖动介绍及实例演示

参考

全面理解MAT(Memory Analyzer)

你可能感兴趣的:(Android 内存泄漏介绍及实例演示)