【问题标题】:How do garbage collectors track all live objects?垃圾收集器如何跟踪所有活动对象?
【发布时间】:2011-07-11 13:19:10
【问题描述】:

垃圾收集涉及遍历已分配对象的列表(所有对象或特定代中的对象)并确定哪些是可访问的。

  1. 如何维护此列表? GC 语言的运行时是否保留了所有对象的巨大列表?

  2. 另外,据我了解,GC 涉及遍历调用堆栈以查找对象引用 - 该算法如何区分支持 GC 的指针和原始数据?

【问题讨论】:

  • 有不同的 GC 策略,最好看一个关于垃圾收集的 wiki 页面:en.wikipedia.org/wiki/Garbage_collection_(computer_science)
  • @keymone 看在上帝的份上,不要阅读关于垃圾收集的维基百科页面。它充满了错误信息。请阅读 Richard Jones 的书:gchandbook.org
  • @JonHarrop 我提到 wiki 只是因为它通常提供大多数主题的高级概述。感谢您的链接。

标签: garbage-collection


【解决方案1】:
  1. 内存管理系统跟踪每个分配对象的大小,就像它在 C 或 C++ 中所做的那样。通常这样做的一种方法是让内存管理系统在每次分配之前分配一个额外的size_t,以跟踪每个对象的大小。内存管理器同样必须跟踪每个空闲块的大小,以便它可以重用块来分配它们。

    垃圾收集器分两个阶段工作:标记阶段和清除阶段。在标记阶段,垃圾收集器开始遍历对象引用,以便找到仍然可以访问的对象。垃圾收集器从存储对象引用和给定名称的几个基本位置(堆栈、全局存储和静态存储)开始,然后遍历对象中的引用。

    在清扫阶段,垃圾收集器从下到上遍历堆,根据size_ts 从分配跳转到分配,并释放任何未标记的内容。

  2. 某些语言(如 Ruby)对所有原语进行标记,以便在运行时与对象引用分开识别它们。其他垃圾收集器非常保守,并且通过它们是对象引用来遵循原语(尽管必须执行一些检查以确保垃圾收集器不会在其他对象中间留下标记)。还有其他语言使用运行时类型信息来更准确地判断它们是否遵循原语。


Ruby 的垃圾收集器有时被称为“保守的”,因为它不检查堆栈上的空间是否实际被使用,因此它有时会通过跟踪堆栈上的幽灵引用来保持死对象存活。但由于它总是知道它所查看的数据是参考数据还是原始数据,所以我在这里并不称其为保守。

【讨论】:

    【解决方案2】:

    垃圾收集涉及遍历已分配对象的列表(所有对象或特定代中的对象)并确定哪些是可访问的。

    不是真的。 GC 分为跟踪和引用计数(参见A unified theory of garbage collection)。跟踪 GC 从一组全局根开始并跟踪所有可从它们到达的对象。引用计数 GC 计算对每个对象的引用数,并在计数达到零时回收它。两者都不需要包含无法访问的对象的列表。

    如何维护此列表? GC 语言的运行时是否保留了所有对象的巨大列表?

    像HLVM 这样的教学解决方案可以保留所有对象的列表,因为它很简单,但这种情况很少见。

    另外,据我了解,GC 涉及遍历调用堆栈以查找对象引用 - 该算法如何区分可 GC 的指针和原始数据?

    同样,有许多不同的策略。保守的 GC 无法区分指针和非指针,因此他们保守地认为非指针可能是指针。像HLVM 这样的教学GC 可以使用像Henderson 的Accurate GC in an uncooperative environment 这样的算法。生产 GC 在 OS 线程堆栈中存储足够的信息,以确定哪些字是指针(以及要跳过哪些堆栈帧,因为它们与托管代码无关),然后使用堆栈遍历器来查找它们。

    请注意,您还必须找到保存在寄存器和堆栈中的本地引用。

    【讨论】:

      【解决方案3】:

      这个网站 (How Java’s Garbage Collector Works?) 对垃圾收集器的工作原理进行了很好的简要说明,而不仅仅是默认的 Java 收集器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-16
        • 1970-01-01
        • 2015-11-02
        • 2012-01-10
        • 2017-08-25
        相关资源
        最近更新 更多