如果JVM在执行GC时继续移动对象,它如何解析引用?

Seb*_*iot 21 java heap garbage-collection jvm

我正在阅读JVM调优,我发现JVM在执行GC时会继续移动对象.但Java对象之间相互引用,人们认为它们是作为指针实现的,但每次移动对象后,JVM都不可能遍历整个堆,并更新所有引用; 肯定会永远.那么它如何解析引用,如果引用没有改变,但对象的物理位置呢?

我已经阅读了很多关于JVM的内容,但在任何地方都没有解释,甚至暗示过.

[编辑]我的观点是,引用是单向的.从指针到指向是"瞬时",但反过来需要完整的堆扫描.虽然有可能,但似乎不太可能.如果10K对象在次要集合中存活,那么执行完整堆扫描需要多长时间才能更新对这些对象的引用10K次?必须使用某种优化的算法或结构.

Ste*_*n C 13

如果你真的对垃圾收集者的工作方式感兴趣,我可以推荐Richard Jones的2本关于垃圾收集的书.链接/参考在这里.这不是特别关于Java垃圾收集.

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


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

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

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

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

    1. 它标志着来自太空的物体.
    2. 它将对象复制到to-space.
    3. 它将对象的地址存储在from-space对象的空间中.(这就像转发地址.)
    4. 它以递归方式访问对象的to-space副本的每个引用字段.

    这是对to-space对象的引用的结果.

  • 如果已经标记了对象,则GC会查找转发地址,然后返回该地址.

GC获取引用的位置(在空间中,或某些GC根目录)然后使用指向空间中对象的指针进行更新.

如果您遵循所有这些,那么您将看到GC不需要查找包含对给定移动对象的引用的所有位置.相反,它只是遇到遍历可到达对象的所有位置.当然,GC 必须这样做遍历,但也有各种技术来减少需要在每个GC周期做横移量.

如果你没有按照上面的说法进行操作,那么请阅读我推荐的一本教科书.他们在解释它方面做得比我能做得好得多.您还可以找到有关其他类型的GC如何处理此问题的材料.


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

(HotSpot GC上发表的论文或其他公共文档并不多,而且大多数存在的材料都假定读者对现代垃圾收集器的工作原理有很好的理解.)