什么是内存泄露
当一个不会被使用的对象,因为某些原因,导致它不能被正常回收,而停留在堆内存中,就产生了内存泄露。
四种引用类型
强引用:任何时候都不会被垃圾回收器回收,如果内存不足,宁愿抛出OutOfMemoryError
软引用:只有在内存将满的时候才会被垃圾回收器回收,如果还有可用内存,垃圾回收器不会回收
弱引用:只要垃圾回收器运行,就肯定会被回收,不管还有没有可用内存
虚引用:虚引用等于没有引用,任何时候都有可能被垃圾回收
Android中常见内存泄露
集合类泄露
如静态的集合类,静态变量所引用的对象不会被回收。
单例造成的内存泄露
如单例对象持有某个activity的引用,导致activity对象无法释放。
非静态内部类造成的内存泄露
如Handler引发的内存泄露,Handler持有外部类的引用,需要使用静态内部类+弱引用来避免。
资源未关闭导致的内存泄露
如广播使用后未关闭,File,Cursor,Stream等资源代码未及时关闭或注销导致。
使用对象池避免内存泄露
在我们需要频繁使用某个类的时候,或者在for循环里创建新的对象时,导致JVM不断创建同一个类。
如我们在使用Message时,不是直接new出来,而是用obtain方法获取。这里用到了享元模式。从消息池里取出可复用的消息,避免产生大量的Message对象。
Context使用不当造成的内存泄露
一般Context造成的泄露,都是因为Context要销毁时,却因为被引用而导致无法回收。
所以正确使用Context的姿势应该是:
- 在Application能搞定的情况下,并且生命周期长的对象,尽量使用Application的Context。
- 不要让生命周期长于Activity的对象持有Activity。
- 尽量不要在Activity中使用非静态内部类。因为非静态内部类会隐式持有外部类的引用,如果使用静态内部类,可以将外部类的弱引用持有。
对于Android应用内存泄露的检测
LeakCanary
项目地址:https://github.com/square/leakcanary
在LeakCanary
中,检测主要分为三步:1.检测一个对象是否是可疑的泄漏对象;2.如果第一步发现可疑对象,dump
内存快照,通过分析.hprof
文件,确定怀疑的对象是否真的泄漏。3.将分析的结果展示