JVM

时间:2022-03-25 20:56:37

无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象的引
用链是否可达,判定对象是否存活都与“引用”有关。 在JDK 1.2以前,Java中的引用的定义很
传统:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块
内存代表着一个引用。 这种定义很纯粹,但是太过狭隘,一个对象在这种定义下只有被引用
或者没有被引用两种状态,对于如何描述一些“食之无味,弃之可惜”的对象就显得无能为
力。 我们希望能描述这样一类对象:当内存空间还足够时,则能保留在内存之中;如果内存
空间在进行垃圾收集后还是非常紧张,则可以抛弃这些对象。 很多系统的缓存功能都符合这
样的应用场景。
在JDK 1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong
Reference)、 软引用(Soft Reference)、 弱引用(Weak Reference)、 虚引用(Phantom
Reference)4种,这4种引用强度依次逐渐减弱。

1. 强引用

强引用就是指在程序代码之中普遍存在的,类似“Object obj=new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。

public class Demo {
public static void main(String[] args) {
Object o = new Object();
System.out.println(o);
System.gc();//通知JVM的gc进行垃圾回收
System.out.println(o);
}
}

控制台输出:

java.lang.Object@1540e19d
java.lang.Object@1540e19d

此时对象没有被回收

2.软引用
软引用是用来描述一些还有用但并非必需的对象。 对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。 如果这次回收还没有足够的内存,才会抛出内存溢出异常。 在JDK 1.2之后,提供了SoftReference类来实
现软引用。

public class Demo {
public static void main(String[] args) {
SoftReference<Object> o = new SoftReference<Object>(new Object());
System.out.println(o.get());
System.gc();//通知JVM的gc进行垃圾回收
System.out.println(o.get());
}
}

控制台输出:

java.lang.Object@1540e19d
java.lang.Object@1540e19d

3.弱引用

弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。 当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。 在JDK 1.2之后,提供了WeakReference类来实现弱引用。

public class Demo {
public static void main(String[] args) {
WeakReference<Object> o = new WeakReference<>(new Object());
System.out.println(o.get());
System.gc();//通知JVM的gc进行垃圾回收
System.out.println(o.get());
}
}

控制台输出:

java.lang.Object@1540e19d
null

说明对象被回收了

4.虚引用

虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。 一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。 为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。 在JDK 1.2之后,提供了PhantomReference类来实现虚引用。
虚引用无法通过 get() 方法来取得目标对象的强引用从而使用目标对象,观察源码可以发现 get() 被重写为永远返回 null。

    /**
* Returns this reference object's referent. Because the referent of a
* phantom reference is always inaccessible, this method always returns
* <code>null</code>.
*
* @return <code>null</code>
*/

public T get() {
return null;
}

PhantomReference 是所有“弱引用”中最弱的引用类型。不同于软引用和弱引用,虚引用无法通过 get() 方法来取得目标对象的强引用从而使用目标对象,观察源码可以发现 get() 被重写为永远返回 null。
那虚引用到底有什么作用?其实虚引用主要被用来 跟踪对象被垃圾回收的状态,通过查看引用队列中是否包含对象所对应的虚引用来判断它是否 即将被垃圾回收,从而采取行动。它并不被期待用来取得目标对象的引用,而目标对象被回收前,它的引用会被放入一个 ReferenceQueue 对象中,从而达到跟踪对象垃圾回收的作用。
所以具体用法和之前两个有所不同,它必须传入一个 ReferenceQueue 对象。当虚引用所引用对象被垃圾回收后,虚引用会被添加到这个队列中。如:


public class Demo {
public static void main(String[] args) {
ReferenceQueue<String> refQueue = new ReferenceQueue<>();
PhantomReference<String> referent = new PhantomReference<>(new String("T"), refQueue);
System.out.println(referent.get());// null
System.gc();
System.runFinalization();
System.out.println(refQueue.poll() == referent); //true
}
}