保守式垃圾收集器

24

我看到有人将垃圾收集器称为很多东西-代际等,但我看到Boehm GC被标记为"保守型"。这究竟是什么意思?

我曾见过许多种垃圾收集器,例如代际垃圾收集器等等,但我看到Boehm GC被标注为“保守型”垃圾收集器。那是什么意思呢?
2个回答

33
一个垃圾回收器必须扫描所有对象和调用(执行堆栈)以识别执行程序中的所有“活动”地址,然后“收集”没有“活动”地址的对象。在某些环境中,GC算法可以是精确的,并且知道什么是对象地址和什么不是。在其他环境中,它必须扫描存储的部分(特别是执行堆栈),其中有可能是对象地址的存储字,并做出保守的假设,如果它看起来像是有效的地址,并且有一个对象具有该地址,则不应该收集该对象。
保守式回收有优点,最显著的是代码生成器(如果不是解释的话)可以更自由地分配变量在何时何地需要它们,而且不需要严格跟踪哪些是对象指针。(需要跟踪对象指针位置可能会导致代码优化不佳,此外还会使代码生成器变得更加复杂。)此外,保守式回收器有一定的机会被用于从未打算支持垃圾回收的编译器,而精确式回收器则需要对编译器进行彻底的更改。
保守方法的主要缺点是无法实现完整的“复制”回收器。在进行复制时,必须更新对复制对象的指针,如果不清楚给定位值是对象指针还是数字值,则无法安全地确定在复制对象时是否应将其修改。此外,有些“死”对象可能最终无法被收集,这是由于随机位模式看起来像它们的地址,但实际上这不是一个严重的问题。

1
如果对象引用被存储为句柄而不是直接指针,则可以实现复制收集器。在缺乏硬件支持的情况下,基于句柄的方法往往比使用直接指针的方法慢,但在具有硬件支持的多处理器系统中,基于句柄的方法可能具有优势。当然,如果试图判断什么可能或可能不是对象引用,则它们将具有巨大优势。 - supercat
@supercat 这种系统有哪些硬件支持? - Pepijn
等等,我似乎记得这个 Java GC 是建立在一个带有硬件写屏障的平台上的。嗯嗯。 - Pepijn
Boehm GC 实现了扫描吗? - Rodrigo Farias Rezino
@SaCi - 谷歌一下:http://en.wikipedia.org/wiki/Boehm_garbage_collector - “该收集器使用标记-清除算法”。 - Hot Licks
显示剩余3条评论

9
保守型垃圾收集器不知道某个单词是否为指针。如果该单词指向已分配的堆块,则垃圾收集器会保守地假定该单词是指针,因此不会回收该堆块或从其可访问的任何内容。
这种方法的主要优点是,它可以收集无法访问的值,而无需与编译器协作。然而,它也有很多缺点:
  1. 一些长得像指针的数值会防止堆的某些部分被回收,导致内存泄漏。在32位地址空间中,这是一个更大的问题,因为如果已分配了GB级别的RAM,几乎每个int都会指向堆块。

  2. 确定某个单词是否指向已分配的堆块需要搜索堆,这是一个缓慢且(客观上)不必要的过程。

  3. GC不能移动堆块,因为它不知道它们所有指针的位置,也因此不能更新指针。

  4. 隐藏指针或在堆块外使用指针的代码会使保守型GC崩溃。这个问题曾经在Numerical Recipes和Boehm GC的C代码中出现,尽管是因为NR C代码违反了C规范。

这些缺点非常严重,以至于在可能的情况下,生产环境的垃圾收集器会尽量避免使用保守型方式。

1
你的第二点是相当错误的。在一个设计良好的设置中,确定指针是否指向有效的分配是非常高效的。 - Hot Licks
@HotLicks:实现通常会搜索一个区间树,这通常会在标记阶段的内部循环中产生几次缓存外存储器读取。与不必在准确收集器中进行搜索相比,这是较慢的。 - J D
我所工作的实现方法可以更高效地完成这项任务。对于小型对象,相似大小的对象被放置在数组中,以便计算对象边界,并根据每个数组的位向量检查对象的有效性。 - Hot Licks
@HotLicks:那只是解决方案的一部分。如果给定一个未知类型对象的(可能是内部的)指针,如何确定它是否“小”,以及(如果适用)要检查哪个位向量? - J D
内部指针在许多方案中都是有害的。但是,通过与位向量相关联的限制进行比较,索引适当的限制并扫描对象边界,通常可以相当有效地确定一个位模式(内部或非内部)是否可能是指针。各种技巧使这变得非常高效。 - Hot Licks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接