2011-10-02 42 views
16

我见过垃圾收集器被标记为很多东西 - 代代等。但是我看到Boehm GC标记为“保守”。这到底是什么意思呢?保守的垃圾收集器

回答

23

垃圾收集器必须扫描所有对象和调用(执行堆栈)以识别正在执行的程序中的所有“活动”地址,然后“收集”没有“活动”地址的对象。在某些环境中,GC算法可能是精确的,并且确切知道什么是对象地址,什么不对。在其他环境中,它必须扫描部分存储(最着名的是执行堆栈),其中有可能是对象地址的存储字,并且假设CONSERVATIVE假设它看起来像一个有效地址,并且存在一个对象地址,那么不应该收集对象。

保守收集有一些优点,最值得注意的是,代码生成器(如果没有解释的话)可以随时随地分配变量,并且不需要严格追踪哪些是对象指针。 (跟踪对象指针位置的需求可能会导致优化程度较低的代码,此外还会使代码生成器变得相当复杂。另外,保守的收集器有一些合理的机会,可用于从未打算支持的编译器垃圾收集,而精确的收集器会要求编译器彻底改变)。

保守方法的主要缺点是不能实现完整的“复制”收集器。复制完成后,必须更新指向复制对象的指针,并且如果不清楚给定位值是否为对象指针或仅是数值,则无法安全地确定该对象是否应该被修改复制。还有一个缺点是,由于随机位模式看起来像他们的地址,一些“死”的对象最终可能不会被收集,尽管在实践中这不是一个严重的问题。

+1

如果对象引用存储为句柄而不是直接指针,则可以实现复制收集器。在没有硬件支持的情况下,基于句柄的方法往往比使用直接指针的方法慢,但在具有硬件支持的多处理器系统中,基于句柄的方法可能具有优势。当然,如果人们试图判断什么可能或可能不是对象引用,它们当然会有巨大的优势。 – supercat

+0

@supercat什么样的系统对此有硬件支持? – Pepijn

+0

@Pepijn:我不知道任何现有的硬件都不会支持这样的事情,而不会强加16,384个对象限制(按照今天的标准,这当然会很可笑)。但是,如果有人正在设计一个旨在优化面向对象框架中的性能的下一代架构,那么适量的硬件就有可能为垃圾收集提供大量的帮助。例如,分代或并发垃圾收集的一个重要要求是知道哪些对象已被修改,因为... – supercat

5

一个保守的垃圾收集器是一个不知道给定的单词是否是一个指针。如果单词指向已分配的堆块,那么垃圾收集器会保守地假定这个单词是一个指针,因此不会回收该堆块或任何被认为可以从中访问的内容。

这种方法的主要优点是它可以收集不可达的值,而不必与编译器协调工作。但是,它有很多缺点:

  1. 看起来像指针的值通过防止部分堆被回收而导致内存泄漏。这对于32位地址空间来说是一个更大的问题,因为如果分配了GB的RAM,几乎每个int都将指向一个堆块。

  2. 确定单词是否指向已分配的堆块需要搜索堆缓慢且(客观)不必要的堆。

  3. GC无法移动堆块,因为它不能更新指针,因为它不知道它们在哪里。

  4. 隐藏指针或在堆块外使用指针的代码会使保守的GC崩溃。数字食谱代码和Boehm GC出现了这个问题,尽管因为NR C代码违反了C规范。

这些缺点严重到足以使生产垃圾收集器尽可能不保守。

+1

你的观点2是相当错误的。在设计正确的设置中,确定指针是否处理有效分配是非常有效的。 –

+0

@HotLicks:实现通常搜索间隔树,通常会在标记阶段的内部循环中引发几个超速缓存内存读取。与不必在准确的收集器中进行搜索相比,这是缓慢的。 –

+0

我工作的实现更有效率。对于小对象,阵列中的大小相似,因此可以计算对象边界,并且可以针对每个阵列的位向量来检查对象有效性。 –