如何理解"relocate objects directly reachable from running code"?

How to understand "relocate objects directly reachable from running code"?

我正在研究将 gc 集成到我的 llvm 项目中,当我阅读 this document 时,一句话让我感到困惑:

However, for a collector which wishes to relocate objects directly reachable from running code, a higher standard is required.

我不明白移动 "relocate objects directly reachable from running code" 试图做什么。

据我所知,概念 "relocate" 表示 gc 指针引用到对象的新位置,例如:

在Java中:

Foo foo = new Foo();

foo = new Foo(); // ---> a relocation happens

谁能解释一下 "relocate objects directly reachable from running code" 想要做什么?

编辑:

关于"relocation"这个概念,文档上没有解释,但是我找到了this document,它是一个由llvm实现的dotnet的编译器,它解释了这个概念:

A GC algorithm is relocating if during a GC, GC pointers may be updated to refer to the new location of an object. An algorithm update pointers found in certain regions but not others. For instance, GC pointers from the stack might not be updated while GC pointers in the heap might be updatable. If the algorithm relocates pointers from all regions, it is fully relocating. When a GC is relocating pointers from some memory region, it necessarily implies the GC reporting is precise in that region.

不知道我理解的对不对"relocation",贴出来给大家参考。

这意味着重新定位地址在函数局部变量中的对象。比如这样:

void doRelevantActions(final Thing t) {
    for(Aspect a : t.getAspects())
        if(a.isRelevant(getCurrentSituation()))
            t.doSomeAction();
}

通常,Aspect 只能从 Thing 到达。但是在那个循环中,局部变量 a 也达到了 Aspect 并且 a 可能在 CPU 寄存器中,因此 GC 可能必须修改 a 的值=30=] 注册以重新定位 Aspect.

在我看来,

在 运行 时修改函数的 CPU 寄存器需要的不仅仅是 "higher standard"。需要魔法棒

我相信 GC 做这种事情是通过确保在某些时候 CPU 寄存器中没有状态,所以停止 运行 线程并修改所有线程的堆栈帧足以重新定位对象。不过,修改堆栈帧仍然不是一件简单的苦差事。

编辑: 也许我误解了你问题的核心?也许你真的想知道搬迁是什么?假设一个对象有 100 个字节大,并且在某个时候,它单独占用一个 8k RAM 页面,因为该页面上的任何其他内容都不可访问。如果 GC 可以将那个 100 字节的对象移动到另一个 8k 的页面,那么它可以释放 8k。该操作称为重定位。

在这种情况下,本文讨论的是在堆中而不是在您的代码中重定位 object。

有很多不同的GC算法,所以让我们以G1的HotSpot为例。

堆被分成两个逻辑区域(世代),young 和 old。年轻一代被廉价收集,因为 Eden space 被视为堆栈。当一个minor GC发生时,objects从Eden复制到一个幸存者space(还在年轻代)。这是 object 重定位,将其从堆的一部分移动到另一部分。 Objects 也从一个幸存者 space 复制到另一个幸存者,直到达到终身阈值。如果仍然被引用,它们将被复制到老年代。

对于主要的 GC 周期,object 会在老年代重新定位以减少空闲 space 的碎片。

Objects 通过 object header 访问,其中包含当前存储 object 的堆中的地址。在搬迁期间,需要更新 object header 以确保其正确。要安全地执行此操作,需要锁定 object header,从而在更新期间阻塞应用程序线程。许多 GC 算法将所有这些更新组合在一起,导致可见的 GC 暂停。

其他算法,例如 Azul(我为之工作)的 Zing 中的 C4,在 object header 上使用读取屏障来消除 GC 暂停。如果您想了解更多详细信息,可以在此处阅读论文 http://go.azul.com/continuously-concurrent-compacting-collector