Fork me on GitHub

Android内存泄露总结

什么是内存泄露

当一个不会被使用的对象,因为某些原因,导致它不能被正常回收,而停留在堆内存中,就产生了内存泄露。

四种引用类型

强引用:任何时候都不会被垃圾回收器回收,如果内存不足,宁愿抛出OutOfMemoryError

软引用:只有在内存将满的时候才会被垃圾回收器回收,如果还有可用内存,垃圾回收器不会回收

弱引用:只要垃圾回收器运行,就肯定会被回收,不管还有没有可用内存

虚引用:虚引用等于没有引用,任何时候都有可能被垃圾回收

Android中常见内存泄露

  • 集合类泄露

    如静态的集合类,静态变量所引用的对象不会被回收。

  • 单例造成的内存泄露

    如单例对象持有某个activity的引用,导致activity对象无法释放。

  • 非静态内部类造成的内存泄露

    如Handler引发的内存泄露,Handler持有外部类的引用,需要使用静态内部类+弱引用来避免。

  • 资源未关闭导致的内存泄露

    如广播使用后未关闭,File,Cursor,Stream等资源代码未及时关闭或注销导致。

  • 使用对象池避免内存泄露

    在我们需要频繁使用某个类的时候,或者在for循环里创建新的对象时,导致JVM不断创建同一个类。

    如我们在使用Message时,不是直接new出来,而是用obtain方法获取。这里用到了享元模式。从消息池里取出可复用的消息,避免产生大量的Message对象。

  • Context使用不当造成的内存泄露

    一般Context造成的泄露,都是因为Context要销毁时,却因为被引用而导致无法回收。

    所以正确使用Context的姿势应该是:

    1. 在Application能搞定的情况下,并且生命周期长的对象,尽量使用Application的Context。
    2. 不要让生命周期长于Activity的对象持有Activity。
    3. 尽量不要在Activity中使用非静态内部类。因为非静态内部类会隐式持有外部类的引用,如果使用静态内部类,可以将外部类的弱引用持有。

对于Android应用内存泄露的检测

LeakCanary

项目地址:https://github.com/square/leakcanary

LeakCanary中,检测主要分为三步:1.检测一个对象是否是可疑的泄漏对象;2.如果第一步发现可疑对象,dump内存快照,通过分析.hprof文件,确定怀疑的对象是否真的泄漏。3.将分析的结果展示