从 JDK1.2 版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:
- 强引用 StrongReference
- 软引用 SoftReference
- 弱引用 WeakReference
- 虚引用 PhantomReference
Android 中采用了标注与清理(Mark and Sweep)回收算法:
从”GC Roots” 集合开始,将内存整个遍历一次,保留所有可以被 GC Roots 直接或间接引用到的对象,而剩下的对象都当作垃圾对待并回收。
在 Android 中,每一个应用程序对应有一个单独的 Dalvik 虚拟机实例,而每一个 Dalvik 虚拟机的大小是固定的(如 32M,可以通过ActivityManager.getMemoryClass()获得)。这意味着我们可以使用的内存不是无节制的。所以即使有着 GC 帮助我们回收无用内存,还是需要在开发过程中注意对内存的引用。否则,就会导致内存泄露。
强引用 StrongReference
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。如代码 String s=”abc” 中变量 s 就是字符串对象”abc” 的一个强引用。只要你给强引用对象 s 赋空值 null, 该对象就可以被垃圾回收器回收。因为该对象此时不再含有其他强引用。
弱引用 WeakReference
弱引用通过类 WeakReference 来表示。弱引用并不能阻止垃圾回收。如果使用一个强引用的话,只要该引用存在,那么被引用的对象是不能被回收的。弱引用则没有这个问题。在垃圾回收器运行的时候,如果对一个对象的所有引用都是弱引用的话,该对象会被回收。
软引用 SoftReference
弱引用和软引用的区别在于:如果一个对象只具有软引用,若内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,才会回收这些对象的内存。
而只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
所以从引用的强度来讲: 强引用 > 软引用 > 弱引用。
虚引用 PhantomReference
一个只被虚引用持有的对象可能会在任何时候被 GC 回收。虚引用对对象的生存周期完全没有影响,也无法通过虚引用来获取对象实例,仅仅能在对象被回收时,得到一个系统通知(只能通过是否被加入到 ReferenceQueue 来判断是否被 GC,这也是唯一判断对象是否被 GC 的途径)。
我们都知道,java 的 Object 类里面有个 finalize 方法,它的工作原理是这样的:一旦垃圾回收器准备好释放对象占用的内存空间,将首先调用其 finalize 方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。但是,问题在于,虚拟机不能保证 finalize 何时被调用,因为 GC 的运行时间是不固定的。
使用虚引用就可以解决这个问题,虚引用主要用来跟踪对象被垃圾回收的活动,主要用来实现比较精细的内存使用控制,这对于 Android 设备来说是很有意义的。比如,我们可以在确定一个 Bitmap 被回收后,再去申请另外一个 Bitmap 的内存,通过这种方式可以使得程序所消耗的内存维持在一个相对较低且稳定的水平。