内存泄漏本质
程序在申请内存后,当该内存不需再使用;但却无法被释放&归还给程序的现象
- 忘记释放分配的内存
- 应用不需要某对象时,该对象仍然保持强引用状态
进程优先级
- 前台进程(与用户正在交互的进程)
- 可见进程
- 服务进程
- 后台进程
- 空进程
–
当进程空间紧张时,会按进程优先级低到高的顺序自动回收进程
最容易引发内存泄漏
- Activity
- Service
- Application
- BroadcastReceiver,ContentProvider虽然不在Context继承树,但其内部会持有Context
常见的内存泄漏原因&解决方法
(1)集合类
List
for ( int i = 0 ; i < 10 ; i++){
Object o = new Object();
objectList.add(0);
o = null;
}
虽释放了集合元素引用的本身:o = null;
但集合List仍然引用该对象,故垃圾回收器GC,依然不可回收该对象
–
解决方案:objectList.clear(); objectList = null;
(2)static关键字修饰的成员变量
使用Application的Context代替Context,使用弱引用
(3)非静态内部类/匿名类
解决方法:
1⃣️将非静态内部类设置为静态内部类
2⃣️将内部类抽取出来封装成一个单例
3⃣️尽量避免非静态内部类所创建的实例 = 静态
(4) 资源对象使用后未关闭
–
原理:很可能Activity作为Context传递给某些类,Activity生命周期结束后,某些类仍然存活并保持着该Activity的引用,Activity是重量级对象,却保持引用无法被回收
避免内存泄漏的一些方法
- 尽量避免使用static变量
- 如果逻辑上允许,则使用弱引用(使用WeakReference类实现,可能会有空指针异常)
- 继续使用static变量,记得在Activity被销毁的时候,释放static变量引用
- 非静态内部类、匿名内部类持有外部类的引用(原理:编译的时候,编译器会自动为内部类构造方法中加上外部类的引用)
- Handler内存泄漏问题(使用弱引用)
垃圾回收算法
- 标记-清除 算法
- 复制 算法
- 标记-整理 算法
- 分代收集 算法