LeakCanary 内存泄漏排查工具

743 阅读2分钟

核心:

  • 0 引用 + 内部类
  • 1 概述
  • 2 使用
  • 3 原理
  • 4 总结

https://github.com/square/leakcanary
https://square.github.io/leakcanary/

“A small leak will sink a great ship.” - Benjamin Franklin

0 引用 + 内部类

0.1 引用

什么是引用?

引用可以用指针的概念来理解

A B 两个对象 , A 内部可以调用 B 的方法就称,A内有B的引用

即 A 内有个B的指针,可以访问到B

0.1.1 强引用

A a = new A(); a 就是指向 new出对象的一个强引用
a = null
此时 new 出的对象就不再被a强引用
进入垃圾回收流程

0.1.2 软引用

内存不够的时候,会回收发现的软引用
此时的软引用可以被回收
回收后会加入到关联到引用队列
信号——内存不够

0.1.3 弱引用

发生gc就会回收
弱引用的对象
并且将回收的对象加入队列

0.1.4 幻引用

随时会被回收


public class Refer {
    @Test
    public void main() throws Exception {

        Object wfOb = new Object();
        Object sfOb = new Object();
        Object pfOb = new Object();

        ReferenceQueue<Object> wfQ = new ReferenceQueue<>();
        ReferenceQueue<Object> sfQ = new ReferenceQueue<>();
        ReferenceQueue<Object> pfQ = new ReferenceQueue<>();

        WeakReference weakReference = new WeakReference<>(wfOb, wfQ);
        SoftReference softReference = new SoftReference<>(sfOb, sfQ);
        PhantomReference phantomReference = new PhantomReference<>(pfOb, pfQ);

        System.out.println("softReference");
        System.out.println(softReference.get() != null);
        sfOb = null;
        System.gc();
        System.out.println(softReference.get() != null);
//        System.out.println(sfQ.poll().get() != null);

        System.out.println("weakReference");
        System.out.println(weakReference.get() != null);
        wfOb = null;
        System.gc();
        System.out.println(weakReference.get() != null);
        System.out.println(wfQ.poll().get() != null);

        System.out.println("phantomReference");
        System.out.println(phantomReference.get() != null);
        pfOb = null;
        System.gc();
        System.out.println(phantomReference.get() != null);
        System.out.println(pfQ.poll().get() != null);

    }
}

0.2 内部类

放在类的内部(成员内部类)
方法的内部(局部内部类)
方法的参数内(匿名内部类)
静态内部类

非静态的内部类可以访问到外部类的成员或方法

说明

内部类中存有外部类的引用

此时需要提防由于内部类的引用存在导致的内存泄漏

1 概述

雪崩时没有一片雪花是无辜的

遇到生命周期敏感的对象

谨慎处理赋值和引用关系

2 使用

添加依赖

dependencies {
  // debugImplementation because LeakCanary should only run in debug builds.
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
}

当泄漏对象达到 threshold 时将会有提示

3 原理

利用 WeakReference 监控对象生命周期

如果 weakReference 引用的对象被回收,就可以在关联的引用队列中找到其引用

当我们监控的Object比如 Activity 执行了 Destroy 后
就又一个弱引用指向他,当指定时间都没有在队列中发现其时,意味着发生了泄漏

官方文档: https://square.github.io/leakcanary/fundamentals-how-leakcanary-works/

4 总结

分析内存泄漏关键在于看 生命周期长短

短命对象被长寿对象引用,短命对象应该被回收的时候,却被引用
导致了内存泄漏

生命周期长短:

  • 线程造成生命周期长

  • handler message的delay发送,存在 messageQueue内

  • 单例造成,单例的生命周期往往和进程同步,单例中引用的都不能被释放

本文使用 mdnice 排版