垃圾回收器在 CLR 4 中的改进

  • Abel Avram
  • 王瑜珩

2009 年 6 月 7 日

话题:.NET语言 & 开发

Maoni Stephens 和 Andrew Pardow 分别是 CLR GC 的开发负责人和项目经理,他们在 Channel 9 的一个采访中介绍了 CLR 4 中的后台 GC 功能。这个功能可以在第一个 GC 运行时启动另一个 GC,从而提高垃圾回收的效率。

目前 GC 有两种工作模式:工作站模式和服务器模式,其中工作站模式还可以设置是否并发执行。

工作站模式 / 非并发执行-当负责分配内存空间的托管线程发现没有足够的内存可以分配时,它会在同一个线程中启动 GC。GC 首先会挂起所有其他的托管线程,然后清理内存,最后再恢复被挂起的托管线程,并交出控制权。

工作站模式 / 并发执行,也叫并发 GC-工作流程与非并发 GC 基本相似,但不会在整个清理周期挂起其他托管线程。这些托管线程依然可以继续运行并申请内存空间,但是会有一些限制,具体限制会在后面解释。存放第 0 代对象的内存池也要比非并发 GC 的大一些,以便满足内存分配的需要。如果没有任何内存可以分配,所有其它的托管线程仍然会被挂起。

Maoni 详细解释了并发 GC

(并发 GC)可以让你在 GC 运行时分配内存,但是不能分配太多-对于小对象来说最多不能超过临时段(ephemeral segment) 的范围。如果我们不做临时对象的垃圾回收,临时对象所占用的空间会达到临时段的上限,这时申请内存空间的托管线程会被挂起,直到并发 GC 结束。

在并发 GC 运行的某些阶段,需要将托管线程挂起两次,这可能会花费一些时间。

服务器模式-在这种情况下,每个 CPU 都对应一个 GC 线程和内存堆。当没有内存可以分配时,负责分配内存的线程会告知相应的 GC 线程,该 GC 线程将会挂起对应 CPU 上的其它托管线程,然后清理内存,最后通知分配内存的线程并恢复它挂起的所有线程。

工作站非并发模式与服务器模式统称为阻塞式 GC,因为 GC 运行时其它代码无法运行。

可以通过设置运行时配置文件来改变 GC 的工作模式,GC 的运行频率可以通过在运行时设置LatencyMode属性来改变,可设置的值为GCLatencyMode枚举的:Batch、Interactive 和 LowLatency。

.NET 4.0 引入了后台 GC(Background GC)。并发 GC 只在当前段上分配内存,通常是 16M。当要分配的内存超过这个限制时,所有的线程将被挂起。后台 GC 允许在做一次完全的垃圾回收(第 0、1、2 代)时,启动另一个对临时段的垃圾回收(第 0 和 1 代),这意味着对另一个内存段进行访问。Maoni 解释道:

后台 GC 是并发 GC 的升级版,它使我们可以在后台 GC 工作时,根据需要启动另一个临时 GC。与并发 GC 相同,后台 GC 只运用于完全的垃圾回收并工作在独立的 GC 线程中,而临时 GC 则是阻塞式 GC,也被称为前台 GC。

服务器版本的后台 GC 将不会出现在 CLR4.0 中,但可能会包含在后续版本中。目前,文档中建议:

在内存超过 2GB 的服务器上,可能需要在 boot.ini 中加入 /3GB 开关,以防出现明明有内存但是却报告内存溢出的问题。

你还可以使用.NET3.5 提供的通知机制,在 GC 将要运行以及完成时得到通知,以便在多台服务器间协调工作,避免被 GC 干扰。

查看英文原文:The Garbage Collector Has Been Improved in CLR4

.NET语言 & 开发