我知道在 Java 中我们有软引用的概念。如果:
1)有一个软引用“sf”指的是一个对象A
2)在对象A中,有强引用指向对象B
3) 对象 A 和 B 未在其他任何地方引用。
根据定义,对象 A 和对象 B 都是“可轻松访问的”,对吗?
然后说我们现在内存快用完了,GC就开始了。GC是否有可能回收对象B而不回收对象A?
如果是这样的话,以后如果我们想通过“sf”访问对象B,它将为null。java如何避免这种情况发生?
我在 java doc 中没有看到任何解释。
我知道在 Java 中我们有软引用的概念。如果:
1)有一个软引用“sf”指的是一个对象A
2)在对象A中,有强引用指向对象B
3) 对象 A 和 B 未在其他任何地方引用。
根据定义,对象 A 和对象 B 都是“可轻松访问的”,对吗?
然后说我们现在内存快用完了,GC就开始了。GC是否有可能回收对象B而不回收对象A?
如果是这样的话,以后如果我们想通过“sf”访问对象B,它将为null。java如何避免这种情况发生?
我在 java doc 中没有看到任何解释。
然后说我们现在内存快用完了,GC就开始了。GC是否有可能回收对象B而不回收对象A?
不会。GC 不会破坏可访问对象中的强引用。(作为回收过程的一部分,它当然会破坏无法访问的对象中的引用。但是您无法观察到这种情况的发生……因为要观察它,您需要该对象仍然可以访问。)
这是包的 javadoc 中此语句的结果java.lang.ref
。
“最后,当一个对象无法通过上述任何方式到达时,它是无法访问的,因此有资格进行回收。”
...其中“上述方式”包括强、软、弱和幻影可达性。
两个突出显示的词表示回收资格是处于无法到达状态的结果。由于其他州都没有提到回收资格,我们得出结论,不可到达性是回收的先决条件。
这当然符合常识。如果(假设地)允许 GC 将可访问对象中的强引用“清空”,则应用程序将不可能在对象进入此状态后安全地使用它们。(考虑空引用在库类的实例中的情况......)
我认为关于跟踪 GC 的基本工作原理的简短介绍应该可以澄清问题。
跟踪 GC(Java 和 .NET 中使用的都属于该类别)有一组所谓的 GC root pointers
,它们是全局变量(在 java 中表示类的静态变量)和堆栈帧中的所有活动变量。GC 遍历这些对象并标记所有活动的对象,即可以通过来自至少一个根指针的引用到达。完成后,所有活动变量都已被标记,其余的可以被垃圾收集。
现在可以通过两种不同的方式处理软引用:a)我们遵循软引用并标记其中的所有对象,或者 b)我们不这样做。究竟发生了什么取决于给定的 JVM 实现,但在确定之后就没有其他区别了。
因此有两种可能的情况:
从文档:
“如果一个对象不是强可达但可以通过遍历软引用来达到,那么它就是软可达的。”
“如果某个对象可以在不遍历任何引用对象的情况下被某个线程访问,则该对象是强可达的”
我认为那很清楚。B 是软可达的,因为它只能通过遍历软引用来达到。