【问题标题】:What will GC do if there is a two level soft referenced object如果存在两级软引用对象,GC 会做什么
【发布时间】:2012-05-22 11:15:52
【问题描述】:

我知道在 Java 中我们有软引用的概念。如果:

1) 有一个软引用“sf”引用了一个对象A

2) 在对象A中,有强引用指向对象B

3) 对象 A 和 B 未在其他任何地方引用。

根据定义,对象 A 和对象 B 都是“可轻松访问的”,对吧?

那么说我们现在内存用完了,GC就开始了。有没有可能GC会回收对象B而不回收对象A?

如果是这样的话,以后如果我们想通过“sf”访问对象B,它将为null。 java如何避免这种情况发生?

我在 java doc 中没有看到任何解释。

【问题讨论】:

  • 我会假设 GC 要么收集 A 和 B,要么不收集它们,因为这符合逻辑,但这只是推测。

标签: java garbage-collection soft-references


【解决方案1】:

我认为关于跟踪 GC 的基本工作原理的简短介绍应该可以清楚地说明问题。

跟踪 GC(Java 和 .NET 中使用的都属于该类别)有一组所谓的 root pointers,它们是全局变量(在 java 中表示类的静态变量)和所有活动变量堆栈帧。 GC 遍历这些对象并标记所有活动的对象,即可以通过来自至少一个根指针的引用到达。完成后,所有活动变量都已被标记,其余的可以被垃圾回收。

现在可以通过两种不同的方式处理软引用:a)我们遵循软引用并标记其中的所有对象,或者 b)我们不这样做。究竟会发生什么取决于给定的 JVM 实现,但在确定之后就没有其他区别了。

因此有两种可能的情况:

  • GC 遵循对 A 的软引用,在这种情况下,两个对象都不会被 GC。
  • GC 不遵循对 A 的软引用(并且没有对它的硬引用)。 A 被 GC,如果没有活动对象引用 B,则 B 被 GC。

【讨论】:

  • 谢谢你说得通。
  • 顺便说一句,唯一真正的 GC 根是 JNI 引用,其余对象(应该)有资格进行 GC(这就是 ClassLoader 有 Vector<Class> classes 的原因)
  • @bestsss 没错,但我认为将所有丑陋的细节都排除在外,可以简化基本理解。我只是希望没有人会问如果静态变量真的是根指针,Hotspot 如何卸载类;)
  • 我认为把所有丑陋的细节都排除在外,可以简化基本的理解 - 完全同意,同时我很讨厌解释基本的东西
【解决方案2】:

那么说我们现在内存用完了,GC就开始了。有没有可能GC会回收对象B而不回收对象A?

没有。 GC 不会破坏可达对象中的强引用。 (作为回收过程的一部分,它当然会破坏无法访问的对象中的引用。但是您无法观察到这种情况的发生......因为要观察它,您需要对象仍然可以访问。)

这是 java.lang.ref 包的 javadoc 中此语句的结果。

“最后,当一个对象无法通过上述任何一种方式访问​​时,它是无法访问的,因此有资格进行回收。”

...其中“上述方式”包括强、软、弱和幻影可达性。

两个突出显示的词表示回收资格是处于无法到达状态的结果。由于其他州都没有提到回收资格,我们得出结论,不可到达性是回收的先决条件。

这当然符合常识。如果(假设地)允许 GC 将可访问对象中的强引用“清空”,那么应用程序就不可能在对象进入此状态后安全地使用它们。 (考虑空引用在库类的实例中的情况......)

【讨论】:

  • 你有说明这个的来源吗?
  • @Jeffrey:它会完全破坏语言语义。如果任何外部部分使用 Wea​​kReference,则程序任何部分中的任何引用都可能在任何时候无明显原因地任意变为 null。这将是可怕的!
  • @StevenSchlansker 它不会影响我程序任何部分的任何引用,只会影响软或弱可达的引用。
  • @Jeffrey 软可到达对象被 GC 或不是。想象一下,如果你突然有部分被 GC 处理但仍然可以访问的对象,那么所有的混乱。来自 if (foo != null) foo.bar(); 之类的 NPE 会很混乱,不是吗?
  • @Stephen 添加了一个关于 GCing 对象 A 的小附录。这很明显,但我认为在此处明确表示不会有害。如果您不喜欢它,请恢复。
【解决方案3】:

来自文档:

“如果一个对象不是强可达但可以通过软引用到达,那么它就是软可达的。”

“如果某个对象可以被某个线程访问而无需遍历任何引用对象,则该对象是强可达的”

我认为这很清楚。 B 是软可达的,因为它只能通过遍历软引用来达到。

Said Docs

【讨论】:

  • 我知道这一点。但我想知道我的第二个更重要的问题的答案。
  • 嗯,不要使用软引用。在强引用缓存中存储对 B 的引用。 A 将被收集。因为图是向下遍历的。没有什么能阻止你收集 A,因为它引用了 B
  • 我并不想解决这个问题。我正在尝试了解 GC 的工作原理
  • GC 是关于在你的场景中的可达性,A 和 B 都符合 GC 的条件,因为它们根据定义是软可达的。如果你在其他地方存储了对 B 的强引用,它就变成了强可达,但 A 仍然是软可达的并且有资格进行 GC。请记住,Java 规范仅根据保证来定义事物,它可以使您需要参考特定的实现以获取有关实际算法的更多细节。查看 Glassfish 和 OpenJDK 参考实现,它有很多关于热点如何做事的重要信息
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-12
相关资源
最近更新 更多