标记和扫描GC有什么问题?

时间:2009-10-23 06:07:24

标签: performance garbage-collection

我正在阅读Steve Yegge's "Dynamic Languages Strike Back"谈话,其中有点批评标记和扫描GC(通过该链接大约5-10%,“Pigs尝试飞行”幻灯片)他们有什么问题?

3 个答案:

答案 0 :(得分:31)

以下是引用引文中提到的各种技术的高级子弹点比较(加上“mark-and-compact”......这是标记和扫描的变体。)

引用计数收集的属性是:

  • PRO - 立即回收垃圾(除了周期)
  • PRO - 垃圾收集暂停较小,如果您可以推迟更新“自由空间”数据结构,则最小化。
  • CON - 需要在大多数指针写入操作上调整引用计数
  • CON - 自由空间永远不会被压缩
  • CON - 因为没有压缩自由空间,必须保持“自由空间”数据结构,这增加了分配和解除分配成本。
  • CON - 不收集循环垃圾,除非应用程序手动打破循环。
  • CON - 在多线程应用程序中更新引用计数非常昂贵。

对于经典的标记和扫描:

  • PRO - 没有指针写入开销
  • PRO - 收集循环数据
  • PRO - 可以避免存储管理并发瓶颈(除了GC)
  • CON - 停止世界垃圾收集
  • CON - 自由空间永远不会被压缩
  • CON - 因为没有压缩自由空间,必须维护“自由空间”数据结构,这会增加分配和解除分配成本。

经典的标记和扫描有时会被修改,以便扫描阶段通过“滑动”非垃圾对象来压缩自由空间。这被称为“mark-sweep-compact”。这很复杂,但是:

  • PRO - 没有指针写入开销
  • PRO - 收集循环数据
  • PRO - 可以轻松避免存储管理并发瓶颈(除了GC)
  • CON - 停止世界垃圾收集
  • PRO - 压缩空间,因此分配便宜
  • CON - 紧凑阶段相当昂贵

现代收藏家(包括典型的世代收藏家)基于标记和复制。这个想法是收集器在“从空间”中追踪对象,将它们复制到“空间”。完成后,“to space”在末尾有一个连续的可用空间块,可用于分配新对象。旧的“从空间”放在一边,以便下次垃圾收集器运行。复制集合的好处是与垃圾对象相关的垃圾收集成本接近于零。

  • CON - 指针写入开销(记录“新一代”指针写入“老一代”对象时)
  • PRO - 收集循环数据
  • PRO - 可以轻松避免存储管理并发瓶颈(除了GC)
  • CON - 停止世界垃圾收集,虽然这可以通过一些运行时开销来降低
  • PRO - 对于分代收集器,你通常GC只是堆的一部分,有很多垃圾,因此GC开销平均较少
  • PRO - 较小的GC暂停(大部分时间)
  • PRO - 压缩空间,因此分配便宜
  • PRO - 压缩比使用滑动压缩机更便宜
  • CON - 您需要为收集器预留额外的对象空间。

分代收集器是指有多个空间(代)的收集器,它们以不同的速率收集。这是基于这样的假设:大多数对象都是在短时间内创建的,然后无法访问。因此,通过垃圾收集包含年轻物体的空间,您可以以相对较低的成本回收相对大量的空间。你仍然需要收集老一代,但这种情况可能不那么频繁。

(标记和扫描收集器可能是分代的,但是回报并不像复制收集器那么大。)

答案 1 :(得分:10)

以下是引用的上下文:

  

分代垃圾收集器就是   我得到了最好的答案,因为   它减少了暂停,坦率地说,   所有的垃圾收集器   今天[新]动态语言   废话。他们是标记和扫描,或   他们被引用计算了。

从引言中,他似乎在谈论相当原始的GC,这不是代际的。世代GC仍然可以进行标记和扫描,但是它们在大部分时间内标记的次数要少得多,这使得它们比“每次标记和扫描世界”要快得多。

假设这是他的意思,我同意 - 但他可以更明确地说出来。请记住,这是一个谈话而不是一个博士论文 - 想出最明确的方式表达自己“在蹄子上”是有点棘手的:))

答案 2 :(得分:5)

他将其与mark-compact对比:

  

分代垃圾收集器是我得到的最好的答案,因为它减少了暂停,坦率地说,今天所有[新]动态语言的垃圾收集器都是废话。它们是标记和扫描,或者它们被引用计数。

普通标记&扫描GC并不是那么好,因为它们存在堆碎片问题。对于支持GC的语言通用的高分配级别,这通常比例如在例如GC语言中更快地出现问题。 C ++,其中很多对象都存在于堆栈中。

那就是说,mark-compact真的是标记和&扫描紧凑,因此术语可能会更好。非压缩收集器通常被称为“保守”以区分它们。