C#.NET垃圾收集无法正常运行?

Jac*_*otb 8 .net c# garbage-collection

我正在Visual Studio 2010中开发一个相对较大的解决方案.它有各种项目,其中一个是XNA Game-project,另一个是ASP.NET MVC 2项目.

对于这两个项目,我面临同样的问题:在调试模式下启动它们后,内存使用率不断上升.它们分别以40和100MB的内存使用量开始,但两者都相对较快地升至1.5GB(分别为10分钟和30分钟).之后它有时会回落到接近初始使用状态,有时它会抛出OutOfMemoryExceptions.

当然,这将表明严重的内存泄漏,所以这是我最初试图发现问题的地方.在不成功地搜索泄漏之后,我试着GC.Collect()定期打电话(大约每10秒一次).在引入这个"黑客"后,内存使用量分别保持在45和120MB 24小时(直到我停止测试).

.NET的垃圾收集应该是"非常好的",但我不禁怀疑它只是不起作用.我使用CLR Profiler试图解决问题,它表明XNA项目似乎已经保存了很多我确实使用的字节数组,但是引用应该已经被删除,因此被垃圾收集集电极.

再次,当我GC.Collect()经常打电话时,内存使用问题似乎已经消失.有谁知道什么可能导致这种高内存使用?它可能与在调试模式下运行有关吗?

Ed *_* S. 14

在不寻常地寻找泄漏之后

更努力=)

托管语言中的内存泄漏可能很难追踪.我对Redgate ANTS Memory Profiler有很好的经验.它不是免费的,但它们会为您提供为期14天的全功能试用版.它有一个很好的UI,可以显示内存分配的位置以及这些对象保存在内存中的原因.

正如Alex所说,事件处理程序是.NET应用程序中非常常见的内存泄漏源.考虑一下:

public static class SomeStaticClass
{
    public event EventHandler SomeEvent;
}

private class Foo
{
    public Foo()
    {
        SomeStaticClass.SomeEvent += MyHandler;
    }

    private void MyHandler( object sender, EventArgs ) { /* whatever */ }
}
Run Code Online (Sandbox Code Playgroud)

我使用静态类来使问题在这里尽可能明显.让我们说,在应用程序的生命周期中,Foo创建了许多对象.每个Foo订阅SomeEvent静态类的事件.

Foo对象可以在同一时间或其他脱落的范围内,但静态类维护经由事件处理程序委托每一个的引用.因此,它们无限期地保持活着.在这种情况下,事件处理程序只需要"取消挂钩".

... XNA项目似乎已经保存了很多我确实使用的字节数组...

你可能在LOH中遇到了碎片.如果您经常分配大型对象,则可能会导致问题.这些对象的总大小可能比分配给运行时的总内存小得多,但由于碎片,会为应用程序分配大量未使用的内存.

我上面链接的探查器会告诉你这是否有问题.如果是,您可能会将其追踪到某处的物体泄漏.我刚刚在我的应用程序中修复了一个显示相同行为的问题,这是因为即使在调用它之后也MemoryStream没有释放其内部.将流包装在虚拟流中并将其清零以解决问题.byte[]Dispose()

另外,说明显而易见的,确保实现Dispose()的对象IDisposable.可能存在本地资源.再次,一个好的剖析器将抓住这一点.

我的建议; 它不是GC,问题出在你的应用程序中.使用分析器,让您的应用程序处于高内存消耗状态,获取内存快照并开始分析.


Est*_*aya 5

首先,GC工作正常,效果很好.你刚刚发现它没有错误.

现在我们已经解决了这个问题,一些想法:

  1. 你使用太多线程吗?
  2. 请记住,GC是非确定性的; 只要它认为需要运行它就会运行(即使你打电话GC.Collect().
  3. 您确定所有参考文献都超出了范围吗?
  4. 你首先在内存中加载了什么?大图像?大文本文件?

你的探查器应该告诉你什么使用了这么多的内存.尽可能多地开始削减最大的罪魁祸首.

此外,每隔X秒调用GC.Collect()是个坏主意,不太可能解决您的实际问题.