Java 中除了普通的强引用,基于 Reference 抽象类还有弱引用、软引用和幻引用。

在 Reference 类装载时,会通过 cinit 启动 Reference Handler 线程,辅助 GC。

private T referent;
volatile ReferenceQueue<? super T> queue;
volatile Reference next;
private transient Reference<T> discovered;

public void run() {
    while (true) {
        processPendingReferences();
    }
}

WeakReference

弱引用在GC的过程中,会被特殊处理。在GC的过程中,以copy gc为例,所有存活的强引用都会被拷到新的survivor区域中,但是弱引用不会被拷贝。

同时会把 WeakReference都使用它的discovered 域串起来,在串的同时,把它的referent设置为 nul,如下图所示。(应该是 GC 使用上帝视角处理)

https://zhuanlan.zhihu.com/p/29415902

  1. JVM如何避免在只有弱引用的情况下,不去拷贝这个对象。
  2. WeakReferent何时加到链表中去?是否应该添加,由什么来决定?
  3. 在既有弱引用,又有强引用的情况下,如何把对象的新地址更新到弱引用中去。

进行GC扫描时,遇到一个存活的WeakRef,发现它所引用的对象没有被forward,这就说明了,这个被引用的对象可能没有强引用在引用它了。我们就先把它放到链表里。

在GC以后对链表再做一次遍历,把还有强引用的情况删掉,并且把它的forward更新到弱引用的位置去。

扫描完成后,JVM会负责把WeakReference对象的引用置为NULL,然后,由ReferenceHandler线程再去处理这个链表。

SoftReference

SoftReference会至少经历1次gc而不被回收。