了解.NET GC和OutOfMemory异常

HH.*_*HH. 4 .net garbage-collection out-of-memory

我正在对我的.NET 2.0 Windows服务应用程序中的OutOfMemory异常进行故障排除.为了更好地理解这个问题,我首先编写了一个简单的.NET WinForm测试应用程序,该应用程序通过构建ArrayList来生成OOM异常,直到抛出OOM异常为止.捕获并记录异常,我可以单击表单按钮再次运行OOME.我发现的奇怪的事情是在第4次运行时,在下一个OOME之前消耗的内存量大约是一半.每次运行时,下面列出的结果都是一致的.Eyeballing TaskManager也确认了这一行为.不幸的是,当试图获得更好的统计数据时,Perfmon冻结了.有人可以解释为什么3次运行后内存限制会降低吗?我对GC的理解相当浅薄.您还可以看到我在多次运行后运行GC.Collect(),但它没有帮助降低限制.

更新:我还发现使用const字符串与每个arraylist项目的新对象有很大的不同.代码很简单:

const string TEST_TEXT = "xxxxxxxxxx";
ArrayList list = new ArrayList();
while (true)
{
    list.Add(TEST_TEXT);
}
Run Code Online (Sandbox Code Playgroud)

启动循环:内存10,350,592

  • 抛出OOM异常
  • 数组大小:134,217,728

结束循环:存储器550,408,192

启动循环:内存550,731,776

  • 抛出OOM异常
  • 数组大小:134,217,728

结束循环:内存551,682,048

启动循环:内存551,813,120

  • 抛出OOM异常
  • 数组大小:134,217,728

结束循环:内存551,772,160

启动循环:内存551,903,232

  • 抛出OOM异常
  • 数组大小:67,108,864

结束循环:内存282,869,760

启动循环:内存283,004,928

  • 抛出OOM异常
  • 数组大小:67,108,864

结束循环:内存282,910,720

GC.Collect手动触发

Start Loop:内存14,245,888

  • 抛出OOM异常
  • 数组大小:67,108,864

结束循环:内存283,344,896

Joe*_*orn 8

以下几点,希望能够为您提供足够的信息来回答您的问题:

  • 尽管它的名称,OutOfMemory异常也可能意味着你没有地址空间作为物理RAM.
  • 所以GC.Collect并没有收集所有优秀的RAM..Net中的垃圾收集 是非确定性的,这意味着无法强制运行时清理所有RAM.
  • .Net中的垃圾收集器是世代的,这意味着当一个对象在收集中存活时,它会向上移动到更高的一代,从而更不可能收集它.
  • 当抛出OutOfMemory异常时,您的数组可能已经存在了几次收集尝试,或者甚至被移动到LargeObjectHeap.
  • 数组大小是固定的.要向阵列添加新元素,必须完全重新分配阵列.(您可以使用类似列表的结构获得更好的测试结果).