7、强引用、软引用、弱引用、虚引用有什么区别?具体使用场景是什么?
从 java 1.2 版本引入 java.lang.ref 包,共 4 种引用,这 4 种引用的级别高低依次为:
强引用 > 软引用 > 弱引用 >虚引用
1)强引用 Strong
Reference强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java 虚拟机宁愿抛出OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
强引用就是我们常使用到的引用,写法如下:
A a = new A();
B b = new B(a);
a = null;
当把 a = null 时,这时 a 不再指向 A 的地址。按道理:当某个对象不再被其它对象引用的时候,会被 GC 回收,而 a = null 时,A 对象不能被回收,B 还依赖于 A,造成了内存泄漏。
2)软引用SoftReference
如果一个对象只具有软引用,只有在内存不够的情况下才会被回收。只要垃圾回收器没有回收它,该对象就可以被程序使用。当JVM 中的内存不足的时候,垃圾回收器会释放那些只被软引用所指向的对象。如果全部释放完这些对象之后,内存还不足,才会抛出 OutOfMemoryError。
软引用非常适合于创建缓存。当系统内存不足的时候,缓存中的内容是可以被释放的。比如考虑一个图像编辑器的程序。该程序会把图像文件的全部内容都读取到内存中,以方便进行处理。而用户也可以同时打开多个文件。当同时打开的文件过多的时候,就可能造成内存不足。如果使用软引用来指向图像文件内容的话,垃圾回收器就可以在必要的时候回收掉这些内存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,JVM 就会把这个软引用加入到与之关联的引用队列中。
软引用与弱引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
3)弱引用Weak Reference
被弱引用关联的对象一定会被回收,也就是说它只能存活到下一次垃圾回收发生之前。弱引用并不能使对象豁免垃圾收集,仅仅是提供一种访问在弱引用状态下对象的途径。这就可以用来构建一种没有特定约束的关系,比如,维护一种非强制性的映射关系,如果试图获取时对象还在,就使用它,否则重新实例化。它同样是很多缓存实现的选择。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
A a = new A();
WeakReference b = new WeakReference(a);//B b = new B(a);a = null;
当a = null时,这个时候A只被弱引用依赖,GC会立刻回收A对象,这就是弱引用的好处,避免内存泄漏。
4)虚引用PhantomReference
又称为幽灵引用或者幻影引用。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用取得一个对象。
为一个对象设置虚引用关联的唯一目的就是能在这个对象被回收时收到一个系统通知。
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生
命周期,不能通过它访问对象。虚引用仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
我们可以通过 get 方法来得到其指定对象,它的唯一作用就是当其指向的对象被回收之后,自己被加入到引用队列,用作记录该引用指向的对象已被销毁。虚引用只能在其指向的对象从内存中移除掉之后才会加入到引用队列。其get方法一直返回 null 就是为了阻止其指向的几乎被销毁的对象重新复活。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
虚引用使用场景主要有两个:
1、它允许你知道具体何时其引用的对象从内存中移除。
2、虚引用可以避免很多析构时的问题。
总结: