垃圾收集器 (GC) 根是如何存储的?

How are garbage collector (GC) roots stored?

我知道如何找到根,但问题是,(AFAIK) 必须在运行时找到它们。为此,您需要一个可能溢出的固定大小的容器或一个可调整大小的容器。我不想使用固定大小的容器,因为很难判断要保留多少 space(这可能很浪费)。可调整大小的容器似乎是最好的,但问题是,GC 在没有足够的 space 时运行,因此可调整大小的容器将无法存储它需要的内容。那么在这些条件下,GC根是如何存储的呢?

GC 根是可以包含引用的堆之外的位置 到堆内的 object 。位置可以是任何可以 存储参考。通常是四八个字节的内存存储 32 位或 64 位地址,但也可以是机器寄存器或 space 在磁盘上。有时一个位置被称为 "slot" 因为你可以“插入 在”恰好是一个参考文献。一位经典的 mark & sweep 收藏家的作品是 首先标记根引用的所有 object,然后继续 从那里追踪。

root 的存储位置和方式取决于 VM,并且非常重要 当您考虑部分 GC、线程和 即时。但从概念上讲它很简单。假设你有一个 Python-like 只有函数和全局变量以及以下代码的语言:

 0: FOO = "hel"
 1: BAR = "hi"
 2: def foo(x):
 3:    y = x + "there"
 4:    <GC HERE>
 5:    return
 6: def bar(x):
 7:    y = x + "lo"
 8:    foo(y)
 9:    return
10: bar(FOO)
11: ...

假设 GC 发生在指示的行上。调用堆栈看起来 像这样:

Return address to line 11
Reference to object "hello"
Return address to line 9
Reference to object "hellothere"

GC 将扫描此调用堆栈以区分 return 地址和引用并标记它找到的 objects。然后它 会对全球参考做同样的事情。它们可以存储在 堆上的字典(散列图)并由单个根引用:

{name("FOO") : "hel", name("BAR") : "hi"}

请注意,存储所有根所需的 space 很小。只有你 需要八个字节(一个引用)用于全局变量和八个字节 调用堆栈上的每个元素。你可以 运行 出栈 space 并得到 堆栈溢出但为堆栈预分配了 256kb 和 适当的尾调用优化是 non-issue.