Java的四种引用变量
在Java中是由JVM负责内存的分配和回收,这是它的优点,同时也是它的缺点(不够灵活,垃圾回收对于编程者来说是不可控)。
在JDK1.2之前,如果一个对象不被任何变量引用,则程序无法再次使用这个对象,这个对象最终会被GC(垃圾回收)。但是如果之后可能还会用到这个对象,就只能去新建一个了,这其实就降低了JVM性能,没有达到最大的优化策略。
从JDK1.2开始,提供了四种类型的引用:强引用、软引用、弱引用、虚引用。主要的目的如下:
- 可以在代码中决定某些对象的生命周期;
- 优化JVM的垃圾回收机制;
强引用
强引用是最普遍的引用,如果一个对象具有强引用,垃圾回收器不会回收该对象,当内存空间不足时,JVM宁愿抛出OutOfMemoryError异常;只有当这个对象没有被引用时,才有可能会被回收。
软引用
软引用用java.lang.ref.SoftReference类来表示。
如果一个对象只具有软引用,则有如下特性:
- 当内存空间足够,垃圾回收器就不会回收它;
- 当内存空间不足了,就会回收该对象。JVM会优先回收长时间闲置不用的软引用的对象,对那些刚刚构建的或者刚刚使用过的软引用对象会尽可能保留;
- 如果回收完还没有足够的内存,才会抛出内存溢出异常。只要垃圾回收器没有回收它,该对象就可以被程序使用;
软引用是用来描述一些有用但并不是必需的对象,适合用来实现缓存,内存空间充足的时候将数据缓存在内存中,如果空间不足了就将其回收掉。
SoftReference对象是用来保存软引用,但它同时也是一个Java对象。当软引用对象被回收之后,SoftReference对象的get()方法返回null,但SoftReference对象本身并不是null,而此时SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。
在SoftReference所对应的软引用的对象被垃圾回收时,JVM会先将SoftReference对象添加到ReferenceQueue这个队列中。当我们调用ReferenceQueue的poll()方法,如果这个队列中不是空队列,那么将返回并移除前面添加的那个Reference对象。
弱引用
弱引用用WeakReference类来表示;
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期,它只能生存到下一次垃圾收集发生之前。当垃圾回收器扫描到只具有弱引用的对象时,无论当前内存空间是否足够,都会回收它。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用也可以和一个引用队列联合使用。
使用场景:一个对象只是偶尔使用,希望在使用时能随时获取,但也不想影响对该对象的垃圾收集,则可以考虑使用弱引用来指向该对象。
虚引用
虚引用用PhantomReference类来表示。
与其他三种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用 的一个区别在于:虚引用必须和引用队列联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
在实际程序设计中一般很少使用弱引用和虚引用,使用软引用的情况较多。这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出等问题的产生。