关于WeakReference规范中“traversing(遍历)”定义的疑问
嘿,这个问题问到点子上了——大部分人只会用WeakReference,很少深究JVM规范里这种细节,我来给你拆解明白。
首先先把规范里的定义摆出来,咱们对着说:
An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference.
这里的核心是:JVM规范里的“traversing a weak reference”,是特指在垃圾回收的可达性分析过程中,沿着JVM标记为「弱引用」的那条专属路径去访问referent——也就是WeakReference父类本身维护的那个弱关联对象,也就是你调用get()能拿到的那个东西。这和我们写代码里“调用方法、访问变量”这种“遍历”完全不是一个层面的概念,是JVM内部的可达性分析规则。
再看你写的Frob子类例子:
public class Frob<X> extends WeakReference<X> { private final X referent; public Frob(X referent) { super(referent); this.referent = referent; } // ... }
你在子类里额外存了一个private final X referent,这个变量是强引用——和WeakReference父类的弱关联半毛钱关系都没有。JVM在做可达性分析时,会把Frob实例当成普通的Java对象看待,它的实例变量referent是强引用链的一部分,优先级远高于弱引用。
那回到你的问题场景:如果程序里唯一指向原referent的引用是Frob实例里的this.referent,那此时原referent是强可达的,根本不满足“weakly reachable”的前提(因为强可达>软可达>弱可达,优先级依次降低)。这种情况下,谈“traversing”完全不成立,因为对象本身还处于强可达状态。
再抠回“traversing”的定义:规范里说的“通过遍历弱引用可达”,仅指JVM顺着WeakReference的弱引用通道找到referent的情况——你子类自己加的强引用,不属于这个“弱引用遍历路径”。哪怕你是通过Frob实例去访问这个变量,这也是走的强引用链,和WeakReference的规范定义无关。
总结一下:
- 规范中的“traversing”是JVM垃圾回收可达性分析的专属术语,只认WeakReference原生的弱引用关联
- 你子类新增的实例变量是强引用,会让原对象保持强可达,和弱可达状态无关
- 这种通过子类实例变量访问原对象的方式,完全不构成规范里说的“traversing a weak reference”
内容来源于stack exchange




