最近在和小伙伴一起维护一个github项目,https://github.com/Moosphan/Android-Daily-Interview。
每天出一道面试题。感兴趣的可以点进去看看。最近要开始整理答案。所以顺手也在这里发布下自己写的相关面试题的答案。
正文开始
什么是内存泄漏
之前看大家的回答,好多把内存泄漏和内存溢出的概念搞混的。我这里简单解释下。Android给每个app分配了一定的内存(有人说谷歌给每个app的默认值是16MB,国内厂商都会对这个值进行改变,想想自己的app显示运行内存200多M,好心虚。)。内存溢出就是,你需要的内存超过了Android系统给每个app分配的内存,也就我们平时说得oom。说得官方一点就是:如果没有足够的内存完成实例,并且也无法再扩展,将会抛出oom。
再说内存溢出。这里用之前答案里的一句话,我觉得很精辟:
无非是生命周期长的对象持有生命周期短的对象的引用,造成生命周期短的对象使用完之后无法释放内存
其实这句话总结的已经很到位了。有一部分人应该知道jvm的回收算法主要是使用标记计数法,和可达性分析。不太清楚的可以看这里:垃圾回收算法,其中老年代主要用标记算法,新生代主要用可达性分析。那么一个对象,生命周期已经结束,但是因为被另一个对象引用,这样可达性分析就会判断这个对象不能被回收,那这个对象在内存中所占有的内存自然也无法释放,这就造成了我们说得内存泄漏。
什么情况造成内存泄漏
- 资源未关闭(cursor,io流等)
- 广播注册后没有反注册
- Handler发消息(特别是延迟消息),消息没有消费掉,且没有remove。
- 静态变量赋值了生命周期短的对象。比如工具类持有Context对象,设置为某个Activity。
- 单例模式持有activity
- 非静态内部类,持有父类引用,造成父类无法回收
内存泄漏会造成什么后果
- 内存资源的浪费
- 可能会oom
- 卡顿(不是说泄漏就一定会卡顿,但是大量的泄漏一定会造成卡顿,特别是IO操作)
- 频繁的GC
如何避免内存泄漏
- 良好的编码习惯,有创建就有销毁,有add就有remove,有注册就有反注册,有绑定就有解绑。一定要成对出现。
- 工具类中使用applicationContext
- try catch 要加finally,对资源进行释放
- 合理使用强,弱,软,虚引用。
- 使用LeakCannery检查