C#垃圾收集器行为

时间:2012-10-01 11:47:10

标签: c# garbage-collection

我们在C#中有一个控制我们设备之一的应用程序,并对此设备发出的信号做出反应。

基本上,应用程序创建线程,处理操作(访问数据库等)并与此设备通信。

在应用程序的生命周期中,它创建对象并释放它们,到目前为止,我们让垃圾收集器处理我们的记忆。我已经读过,强烈要求让GC在没有干扰的情况下完成它的工作。

现在我们面临的问题是,我们的应用程序流程逐渐增长,逐步增长。例如:

enter image description here

当应用程序增长时似乎有“波浪”,突然之间,应用程序释放了一些内存,但似乎同时留下了内存泄漏。

我们正试图用一些内存分析器来研究应用程序,但我们想深入了解垃圾收集器的工作原理。

你们是否知道另一篇非常深入的GC文档?

修改:

以下是说明应用程序行为的屏幕截图:

你可以清楚地看到我们对非常规模式的“波浪”效应。

附属问题:

我已经看到我的GC Collection 2 Heap非常大,并且遵循与我的应用程序使用的总字节数相同的模式。我想这是完全正常的,因为我们的大多数对象将至少存活2个垃圾收集(例如Singleton类等)......你怎么看?

3 个答案:

答案 0 :(得分:1)

您描述的行为是在大对象堆(LOH)上创建的对象的典型问题。但是,您的内存消耗似乎会在稍后返回到较低的值,因此请检查两次是否真的是LOH问题。

你显然知道这一点,但不太明显的是LOH上的对象大小有例外。

如文档中所述,大小超过85000字节的对象最终在LOH上。但是,出于某种原因(可能是'优化')超过1000个元素的双精度数组也会在那里结束:

double[999] smallArray = ...; // ends up in 'normal', Gen-0 heap
double[1001] bigArray = ...; // ends up in LOH

这些数组可能导致LOH碎片化,这需要更多内存,直到出现内存不足异常。

由于我们有一个应用程序接收了一些传感器读数作为双精度数组导致LOH碎片整理,因为每个数组的长度略有不同(这些是不同频率的实时数据读数,非实时采样)处理)。我们通过实现自己的缓冲池解决了这个问题。

答案 1 :(得分:1)

我对几年前教授的课程进行了一些研究。我不认为参考文献包含有关LoH的任何信息,但我认为值得以任何方式分享它们(见下文)。此外,我建议在指责垃圾收集器之前执行第二次搜索未发布的对象引用。只需在类终结器中实现一个计数器,就可以检查这些大对象是否正在被丢弃。

此问题的另一种解决方案是,永远不会释放大型对象,而是使用pooling strategy重复使用它们。在我狂妄自大的情况下,我有很多次因为我的应用程序的内存需求随着时间的推移过早地将GC过早地归咎于GC,但这通常不是执行错误的症状。

GC参考文献: http://blogs.msdn.com/b/clyon/archive/2007/03/12/new-in-orcas-part-3-gc-latency-modes.aspx http://msdn.microsoft.com/en-us/library/ee851764.aspx http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx http://blogs.msdn.com/b/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx

Eric Lippert的博客特别有趣,详细了解C#!

答案 2 :(得分:0)

以下是我的部分调查的更新内容:

在我们的应用程序中,我们使用大量线程来完成不同的任务。其中一些线程具有更高的优先级。

1)我们正在使用并发的GC,我们尝试将其切换回非并发

我们看到了戏剧性的改进:

  • 垃圾收集器经常被调用,而且当它被更频繁地调用时,它会释放出更好的记忆。

我会尽快发布截图,以便说明这一点。

我们找到了一篇非常好的文章on the MSDN。我们还在SO上找到了一个有趣的问题。

使用下一个Framework 4.5,将有4种可能用于GC配置。

  1. 工作站 - 非并发
  2. 工作站 - 并发
  3. 服务器 - 非并发
  4. 服务器 - 并发
  5. 我们将尝试切换到“服务器 - 非并发”和“服务器 - 并发”,以检查它是否为我们提供了更好的性能。

    我将根据我们的调查结果更新此主题。