为什么会发生内存泄漏
内存空间使用完毕之后未回收, 会导致内存泄漏。有人会问:Java不是有垃圾自动回收机制么?不幸的是,在Java中仍存在很多容易导致内存泄漏的逻辑(logical leak)。虽然垃圾回收器会帮我们干掉大部分无用的内存空间,但是对于还保持着引用,但逻辑上已经不会再用到的对象,垃圾回收器不会回收它们。
例如
- 忘记释放分配的内存的。(Cursor忘记关闭等)。
- 应用不再需要这个对象,未释放该对象的所有引用。
- 强引用持有的对象,垃圾回收器是无法在内存中回收这个对象。
- 持有对象生命周期过长,导致无法回收。
Java判断无效对象的原理
Android内存回收管理策略图:
图中的每个圆节点代表对象的内存资源,箭头代表可达路径。当圆节点与 GC Roots 存在可达路径时,表示当前资源正被引用,虚拟机是无法对其进行回收的(如图中的黄色节点)。反过来,如果圆节点与 GC Roots 不存在可达路径,则意味着这块对象的内存资源不再被程序引用,系统虚拟机可以在 GC 过程中将其回收掉。
从定义上讲,Android(Java)平台的内存泄漏是指没有用的对象资源任与GC-Root保持可达路径,导致系统无法进行回收。
内存泄漏带来的危害
- 用户对单次的内存泄漏并没有什么感知,但当泄漏积累到内存都被消耗完,就会导致卡顿,崩溃。
- 内存泄露是内存溢出OOM的重要原因之一,会导致Crash
Android中常见的可能发生内存泄漏的地方
1.在Android开发中,最容易引发的内存泄漏问题的是Context。
比如Activity的Context
,就包含大量的内存引用,一旦泄漏了Context
,也意味泄漏它指向的所有对象。
造成Activity泄漏的常见原因:
- Static Activities
在类中定义了静态Activity变量,把当前运行的Activity实例赋值于这个静态变量。
如果这个静态变量在Activity生命周期结束后没有清空,就导致内存泄漏。
因为static变量是贯穿这个应用的生命周期的,所以被泄漏的Activity就会一直存在于应用的进程中,不会被垃圾回收器回收。
static Activity activity; //这种代码要避免
- 单例中保存Activity
在单例模式中,如果Activity经常被用到,那么在内存中保存一个Activity实例是很实用的。但是由于单例的生命周期是应用程序的生命周期,这样会强制延长Activity的生命周期,这是相当危险而且不必要的,无论如何都不能在单例子中保存类似Activity的对象。
举例:
public class Singleton {
private static Singleton instance;
private Context mContext;
private Singleton(Context context){
this.mContext = context;
}
public static Singleton getInstance(Context context){
if (instance == null){
synchronized (Singleton.class){