前言
之前写过一篇文章简要谈了下内存泄漏的产生以及解决方式,今天再来谈谈内存泄漏。
内存泄漏如何产生
生命周期长的对象持有了生命周期短的对象的引用,导致生命周期短的对象在应该销毁的时候并没有销毁
内存泄漏会带来什么问题
对于一个APP而言,偶尔一两个内存泄漏不会有明显的现象。我们可以将内存泄漏按照严重程度分为三个阶段
- 阶段1,偶尔几个页面没有回收,感受不到明显变化
- 阶段2,内存泄漏积累到一定程度,导致应用很容易达到GC临界值,频繁GC导致卡顿
- 阶段3,累积到更多的程度,导致OOM应用崩溃。
内存泄漏如何定位
引入LeakCanary,在运行的过程中,它会自动帮你收集。
内存泄漏如何解决
从产生原因思考解决方案,明显有两种方式:
- 1.生命周期。将被持有引用的对象的生命周期调整到能覆盖持有它的引用的对象的生命周期。
- 2.该销毁时就销毁。生命周期长的对象不直接持有生命周期短的对象的引用,改为持有生命周期短的对对象的弱引用
一个内存泄漏的小例子
单例持有Activity或有Activity inflate出来的view的引用。
- Toast被封装成基本库后,生命周期长于Activity。如果传入的自定义view是Activity inflate出来的,Toast在Show之后并不会手动将Toast实例中保存的自定义View的引用设置为null, Activity没法正常销毁。
- 解决:将Activity换成ApplicationContext,此时View的生命周期与Activity不相关,Activity能正常销毁。
更进一步
有时候会发现内存并没有泄漏,但是LeakCanary告诉你,有些Class never GC but not Leaked。这种就可能是因为在修复内存泄漏问题的时候,使用的是修改生命周期的方式,将被引用对象的生命周期延长了,虽然看起来确实没有内存泄漏了,但是本质上并没有解决问题,因为常驻内存增加了。这种情况下咱们还是不要改对象的生命周期为好,尽量使用弱引用的方式来代替。