2009-08-26 73 views
4

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

更新:我还发现使用常量字符串与每个数组列表项目的新对象有很大的区别。代码很简单:

const string TEST_TEXT = "xxxxxxxxxx"; 
ArrayList list = new ArrayList(); 
while (true) 
{ 
    list.Add(TEST_TEXT); 
} 

开始循环:内存10350592

  • OOM抛出异常
  • 数组大小:134217728

结束循环:内存

开始循环:存储器550731776

  • OOM抛出异常
  • 数组大小:134217728

END LOOP:存储器551682048

开始循环:存储器551813120

  • OOM例外引发
  • 数组大小:134217728

END LOOP:存储器551772160

开始循环:存储器551903232

  • OOM抛出异常
  • 数组大小:67108864

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

开始循环:存储器283004928

  • OOM抛出异常
  • 数组大小:67108864

END LOOP:存储器282910720

GC。收集手动触发

开始循环:内存

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

结束循环:内存

+0

那么你的测试程序做什么呢?它如何“建立一个数组”? – jalf 2009-08-26 18:39:57

+0

请发布您的代码。 – 2009-08-26 18:41:38

+0

查看上面的代码示例。 – 2009-08-27 13:55:44

回答

8

这里有几个这些点合在一起有希望给予y OU足够的信息来回答你的问题:

  • 尽管它的名字,OutOfMemory exceptions are just as likely to mean you are out of Address Space as physical RAM.
  • GC.Collect的不收集所有优秀的RAM。在.net中的垃圾收集是非确定性,意思是有没有办法运行清理所有您的RAM。
  • .NET中的垃圾收集器是,当对象生存收集它向上移动到较高的生成,使得它甚至不太可能被收集的意思。
  • 通过你的内存溢出的异常被抛出的时候,你的阵列有可能已经生存了几集的尝试或者甚至被移到LargeObjectHeap。
  • 阵列大小是固定的。要将新元素添加到数组中,您必须完全重新分配数组。 (使用像列表这样的结构可以获得更好的测试结果)。
3

由于您正在构建数组,因此我假设您正在为每次运行构建一个大数组。如果是这种情况,它将被存储在大对象堆中(因为它将大于85000字节)。 LOH并非像世代堆一样压缩,所以您看到的大小下降可能是由于堆碎片造成的。

+0

对不起 - 我实际上使用ArrayList。见上面的代码。 – 2009-08-27 13:58:54

+0

现在几乎没有理由使用ArrayList,但在这种情况下它并没有真正的区别,castro ArrayList也在内部使用数组。 – 2009-08-27 15:30:17