当前位置: 首页 > 面试题库 >

如果JVM在执行GC时一直在移动对象,那么它如何解析引用?

淳于禄
2023-03-14
问题内容

我正在阅读JVM调优,我发现JVM在执行GC时会不断移动对象。但是Java对象之间有相互引用,可以假定它们是作为指针实现的,但是JVM每次移动对象并更新所有引用后,都不可能遍历整个堆。当然,这将永远。那么,如果引用不变,但对象的物理位置却发生变化,它将如何解析引用?

我已经阅读了很多有关JVM的文章,但是从来没有在任何地方解释甚至暗示过它。

[编辑]我的观点是引用是单向的。从指针到指针是“瞬时”的,但是从另一方向走则需要完整的堆扫描。虽然有可能,但似乎不太可能。如果10K个对象在次要收集中幸存下来,则进行全堆扫描10K次以更新对这些对象的引用需要花费多长时间?必须使用某种优化的算法或结构。


问题答案:

如果您真的对垃圾收集器的工作方式感兴趣,我可以推荐理查德·琼斯的两本有关垃圾收集的书。链接/参考在这里。这不是专门关于Java垃圾收集的。

(我有一本旧书的副本,而新书在我的购物清单上。)

这是复制收集器如何处理此问题的简单版本。

复制收集器通过将对象从一个空间(“从”空间)复制到另一个空间(“到”空间)来工作。

具体来说,GC从每个GC根开始,在“从”空间内遍历可访问对象的图形。每次找到对节点的引用(在实例字段,静态字段,堆栈框架等中)时,它都会检查该引用指向的对象,以查看其是否已标记为已访问。

  • 如果尚未标记,GC将执行以下操作:

    1. 它在起始空间中标记对象。
    2. 它将对象复制到目标空间。
    3. 它将对象的地址存储到起始空间对象中的空间中。(这就像一个转发地址。)
    4. 递归地访问对象的空间副本的每个参考字段。

其结果是引用到空间对象。

  • 如果该对象已被标记,GC将查找转发地址,并返回该地址。

然后,使用指向to-space中对象的指针来更新GC引用来源的位置(在to-space或某个GC根目录中)。

如果您遵循所有这些方法,那么您将发现GC不需要去寻找所有拥有对给定移动对象的引用的位置。相反,它仅遇到遍历可到达对象的所有位置。当然,GC 确实
必须进行遍历,但是有各种技术可以减少每个GC循环中需要进行的遍历量。

如果您未遵循上述说明,请阅读我推荐的其中一本教科书。他们会比我做得更好。您还将找到有关其他种类的GC如何处理此问题的材料。

虽然Java HotSpot的GC是 所有
这种或那种形式的复制收藏。对于并行和并发收集,事情要比我上面的描述要复杂得多,但是“转发地址”机制对所有它们都是通用的。

(关于HotSpot GC的出版物或其他公共文档并不多,并且现有的大多数材料都假定读者对现代垃圾收集器的工作原理有很好的了解。)



 类似资料:
  • 问题内容: 查理·亨特(Charlie Hunt)在他的演讲中说,大型对象对JVM GC不利。因为: 大对象的分配和初始化非常昂贵。 不同大小的大对象可能会导致Java堆碎片化。 如何定义大对象?我怎么知道物体是否是大物体?谢谢 问题答案: 该定义取决于平台,JVM和JVM配置。例如,以下摘自Michael Kopp 的三篇大型JVM 博客文章 中的“垃圾回收如何不同” : 大小物体 JRocki

  • 我正在用GridLayout做一个程序。在执行操作后,我尝试将按钮移动到另一个位置时出现问题。基本上,我在面板上有一个按钮大小的空白区域。我想把点击的按钮移到这个空白处,反过来,这个空白处会取代这个按钮。我正在使用一个数组来获得一个看起来像框架的模型。所以我知道空空间在我的数组中的位置(在JButton数组中是一个空值),我试图让这个按钮在数组中取空空间的位置,并反过来。但它并没有真正起作用。 任

  • 问题内容: 数组: 如何在C#中解析上述json响应 问题答案: 在您提供的字符串 不正确 的格式,该阵列应该是: 您可以使用将其转换: 该工具在nuget中也可用。 如果要使用强类型:

  • 问题内容: 我在从JSON对象提取值时遇到一些问题。这是我的代码 被声明为。代码运行时显示。如果将鼠标悬停在调试模式下,则可以看到对象中的所有值和名称。 我也试过 这回来了。即使将鼠标悬停在对象上,我也可以读取对象中的值。 这是我将使用的JSON字符串的示例。 问题答案: 最后,我使用而不是来解决它,然后将其强制转换为。

  • 问题内容: 我经常听到这些方法(和)返回对象的地址,或者从该地址快速计算出的值;但是我也很确定垃圾收集器会移动并压缩对象。由于哈希码不能改变,因此存在问题。我知道这不是日常工作中需要了解的内容,但我想了解内部知识。那么,有谁知道这是如何用Java实现的?或.NET,因为它们可能相似。 问题答案: .NET的实现有意未发布(当您尝试对其进行反编译时,您会发现它进行了非托管框架调用)。这样的唯一文档在