Android内存泄露

Android内存泄露

参考文章/书籍:

  1. Android开发艺术探索
  2. http://www.jianshu.com/p/c49f778e7acf

最近在看Android开发艺术探索这本书,所以总结一下部分知识:

1、静态变量导致的内存泄露问题

内存泄露的原因:

  1. 非静态内部类会默认对外部类持有强引用;
  2. 外部类创建一个静态的内部类对象:ic

综上:外部类和内部类相互持有,导致静态实例ic会一直持有该Activity的引用,导致该Activity的内存资源不能正常回收。

Eclipse运行后导出内存分析后的hprof文件。

注意:导出的hprof文件后,并不能使用它来进行分析,因为它不能被MAT直接识别,需要通过Android SDK中提供的hprof-conv工具来转换一下;

然后用MAT工具分析:

可以看出来泄露的MainActivity,为什么GC没有回收它呢?
继续看~
选择其中一条继续分析:
点击结果中的第一条,然后单击右键选择Path to GC roots->exclude weak/soft references

(之所以选择exclude weak/soft references,是因为两者都有较大几率被gc回收掉,它们并不能造成内存泄露。)

分析上述结论:
This$0:这是内部类对当前类MainActivity的引用;
这个内部类就是ic(InnerClass);
mContext被当前类MainActivity引用;

综上:外部类MainActivity和内部类ic相互保持持有,导致内存泄露;

解决办法:

在onDestroy方法中将静态对象置空。

注意:在Dalvik虚拟机追踪,static变量所指向的内存引用,如果不把它设置为null,GC是永远不会回收这个对象的。

再查看内存泄露hprof文件:

现在就只有一个MainActivity实例了。


2.单例模式导致的内存泄露

单例模式创建对象instance,然后两秒中之后关闭MainActivity。

内存泄露的原因:

普通的单例模式在创建时,由于需要传入一个Context,所以这个Context的生命周期的长短至关重要:
因为如果此时传入的是Activity的Context,当这个Context所对应的Activity退出时,由于该Context的引用被单例对象所持有,其生命周期等于整个应用程序的生命周期,所以当前Activity退出时它的内存并不会被回收,这就造成内存泄露。

解决方法:

传入Application的Context,而非Activity的Context。
因为如果此时传入的是Application的Context,因为Application的生命周期就是整个应用的生命周期,所以这将没有任何问题。


3、属性动画导致的内存泄露

内存泄露的原因:

Android3.0开始,Google提供的属性动画中有一类无限循环的动画,如果在Activity中 播放此类动画且没有再onDestory中去停止动画,那么动画会一直播放下去,尽管已经 无法再界面上看到动画效果了,并且这个时候Activity的View会被动画劫持,而View 又持有了Activity,最终Activity无法释放。

解决方法:

在Activity的onDestroy中调用animator.cancel()来停止动画。