【问题标题】:How are garbage collector (GC) roots stored?垃圾收集器 (GC) 根是如何存储的?
【发布时间】:2020-05-31 23:29:55
【问题描述】:

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

【问题讨论】:

  • 为什么要存储它们?这不是一个滑稽的问题。例如,堆栈上的每个引用都是一个根,但它们都位于堆栈上,并且它们不会去任何地方(只要您正在执行 stop-the-world 集合)。
  • @rici -- 你在说什么堆栈?栈和堆栈?
  • 您确实知道每次 GC 调用都会发现 GC 根,对吗? GC 结构也位于堆外部,而 GC 操作 on 堆。
  • @Eugene -- 请原谅我的无知,但是您所说的 GC 根在每次 GC 调用时都会被发现 是什么意思?你的意思是每次分配
  • 最明显的一个是:堆栈引用。如果堆栈上有东西,它显然正在使用中。因此,这是根的完美候选者。为了找到这些,当然需要扫描线程堆栈。为了准确起见,这些文件会在您的应用程序冻结时进行扫描。

标签: memory compiler-construction garbage-collection containers gc-roots


【解决方案1】:

GC 根是堆外可以包含引用的位置 到堆内的一个对象。位置可以是任何可以 存储参考。通常是四个或八个字节的内存存储 32 位或 64 位地址,但也可以是机器寄存器或空间 在磁盘上。有时一个位置被称为“槽”,因为您可以“槽 in" 正是一个参考。经典的mark & sweep 收藏家作品 首先标记根引用的所有对象,然后继续 从那里开始追踪。

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

 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 会扫描这个调用栈来区分返回 地址和引用并标记它找到的对象。然后它 会对全局引用做同样的事情。它们可以存储在一个 堆上的字典(哈希图)并由单个根引用:

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

请注意,存储所有根所需的空间很小。只有你 全局变量需要 8 个字节(一个引用),需要 8 个字节 调用堆栈上的每个元素。您可以用完堆栈空间并获得 堆栈溢出,但为堆栈预分配了 256kb 和 适当的尾调用优化不是问题。

【讨论】:

    猜你喜欢
    • 2020-02-08
    • 2011-07-16
    • 1970-01-01
    • 2014-08-26
    • 2023-03-30
    • 1970-01-01
    • 2012-02-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多