Android中的内存泄漏
内存泄漏的定义
不再使用的对象持续占用内存或者内存得不到及时释放,从而造成内存空间的浪费称为内存泄漏。严重时会产生OOM。
内存泄漏的根本原因
长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏,尽管短生命周期对象已经不再需要,但是因为长生命周期持有它的引用而导致不能被回收。
常见的内存泄漏
1、如果构造单例模式需要传入Context上下文对象,必须传入全局的Application.Context对象,保证两者的生命周期都一样长,避免传入Activity.Context对象导致内存泄漏。
2、类中持有静态变量,并且持有Activity的引用,导致两者生命周期不一致,出现内存泄漏。
3、Java机制中的非静态内部类会默认持有外部类的引用,当非静态内部类的生命周期比外部类的生命周期长的时候,会导致内存泄漏(常见非静态Handler发生内存泄漏,避免方法:采用静态内部类 + 弱引用 + Activity的销毁回调方法中remove掉Handler)。
4、非静态内部类会默认持有外部类的引用导致内存泄漏的另外两种形式:
(1)在Activity中注册广播,当Activity销毁后未及时取消注册,会导致内存泄漏。
(2)注册观察者模式,销毁时未取消注册,会导致内存泄漏,如Retrofit+RxJava注册网络请求的观察者回调。5、Timer和TimerTask导致内存泄露:当我们Activity销毁的时,有可能Timer还在继续等待执行TimerTask,它持有Activity的引用不能被回收,因此当我们Activity销毁的时候要立即cancel掉Timer和TimerTask,以避免发生内存泄漏。
6、资源未关闭或释放导致内存泄露:IO操作、数据库操作要及时关闭。
7、属性动画造成内存泄露。在属性动画中可以播放无限循环的动画,如果在Activity中播放此类动画且没有在onDestroy()方法中停止动画,那么动画会一直播放下去,尽管在界面上无法看到动画效果,但此时属性动画会持有View的引用,而View又持有了Activity的引用,最终导致Activity无法释放,造成内存泄漏。(解决办法:在onDestroy()方法中调用animator.cancel()方法关闭动画)
8、WebView造成内存泄露。
内存泄漏分析工具
AS内置的Android Profile可以直观查看内存变化情况以及堆栈信息。
Heap Dump 右边四列的意思分别如下:
Alloc Count:Java堆中的实例个数
Native Size:native层分配的内存大小
Shallow Size:Java堆中分配实际大小
Retained Size:这个类的所有实例保留的内存总大小(并非实际大小)