openjdk中引用对象的referent字段由jvm在gc时直接清空,非java代码控制;softreference在内存不足时清空,weakreference在每次gc中若仅弱可达即清空,phantomreference构造时referent即为null。

OpenJDK 中的引用(SoftReference、WeakReference、PhantomReference)本身不“找”对象,而是被 GC 主动识别和处理;它们能否访问到对象,取决于 GC 是否已将其从引用链中切断。
引用对象内部怎么存目标对象?
所有 Reference 子类都继承自 java.lang.ref.Reference,其核心字段是 referent——一个用 volatile 修饰的 Object 类型字段。JVM 在构造 SoftReference<string> ref = new SoftReference(new String("hi"))</string> 时,会把那个 String 实例的地址写入 ref.referent。
但关键点在于:referent 字段在 GC 过程中会被 JVM 直接清空(设为 null),不是靠 Java 代码逻辑控制的。这个动作发生在 GC 判定该引用类型对应的对象“可回收”之后、实际回收之前。
-
SoftReference:仅在内存不足且经过二次标记后才清空referent -
WeakReference:只要本轮 GC 发现它只被弱引用链可达,就立刻清空referent -
PhantomReference:构造时referent就被设为null,永远无法通过get()拿到对象
为什么 get() 有时返回 null?
调用 ref.get() 本质就是读取 referent 字段。它返回 null 并不表示“找不到”,而是表示 JVM 已经在某次 GC 中把它清掉了。常见误判场景:
- 多线程环境下未同步检查:线程 A 调用
ref.get()得到非 null 对象,线程 B 紧接着触发 GC,随后线程 A 再次调用ref.get()就可能为null - 误以为
WeakReference能“延迟释放”:它在每次 GC 都可能被清空,哪怕刚创建不到 1ms - 对
SoftReference的“内存不足”判断有误解:不是堆满才触发,而是 GC 后仍无法满足分配请求时才批量清理软引用
GC 是怎么识别并处理这些引用的?
JVM 在可达性分析阶段会把所有 Reference 实例单独拎出来,按强度分级处理:
- 先标记所有强可达对象
- 再扫描剩余对象:若只被
SoftReference引用,则暂挂入“待软清理队列” - 若只被
WeakReference引用,直接加入“待清除队列”,并在本轮 GC 结束前清空referent - 所有被清空
referent的引用实例,会被放入各自注册的ReferenceQueue(如果构造时传入了)
这个过程完全由 JVM 原生代码实现,不走 Java 字节码逻辑。你写的 ref.get() 只是读一个字段,而字段是否还有效,全看 GC 上一轮有没有动过它。
容易忽略的底层事实
引用对象本身(比如 WeakReference 实例)也是普通 Java 对象,存在堆上,有自己的 Mark Word 和类指针。一旦它自己变成不可达,连带它的 referent 字段也彻底失去意义——这时即使 referent 还没被清空,你也再没机会访问它了。
真正决定“能不能找到对象”的,从来不是引用类的方法,而是 GC Roots 到目标对象之间是否存在至少一条**未被中断的强引用链**。其他引用类型只是给这条链加了“断开开关”,而开关由 GC 控制,不是由你控制。











