我是如何解决这个内存泄漏问题的?

时间:2013-09-03 15:02:15

标签: c# .net memory-leaks .net-2.0

我有一个.net 2.0应用程序,可以执行一些繁重的处理,使用大量内存,并且可以执行更多操作。它从Web服务中获取任务,完成任务,返回结果,并将所有内容重复到无穷大。

可以通过此

简化和说明主代码结构
while (true) 
{
     Task t=ServiceAccess.GetTask();
     if (t.TaskType == 1)
     {
          BrutalMemoryConsumerProcessor b=new BrutalMemoryConsumerProcessor();
          b.DoTask(t);
     } 
     else if (t.TaskType == 2)
     {
          HeavyCPUConsumerProcessor h=new HeavyCPUConsumerProcessor();
          h.DoTask(t);
     }
}
对我来说幸运的是,它在内部代码中某处OutOfMemoryException几个周期后死亡。这是因为两个对象都已经过校准,几乎可以使用所有的RAM(对于x86应用程序),并且在创建新对象实例时使用旧对象实例是进程扼杀的可靠方法。

好的,所以我先尝试了一些技巧。即:

GC.Collect();

在循环开始时,就在while (true)之后。

没有运气。

接下来,我记得很久以前的旧版VB6 COM,并在b = null;语句块的范围内尝试了h = null;if

再也没有运气。

结合,没有骰子。

解雇了内存分析器。我有一段时间没有使用它,所以我需要浏览几页“程序文件”才能找到它。它是YourKit Profiler。好玩具......

无论如何,在经过一些干预之后,它告诉我对bh的引用仍留在本地“堆栈范围”内。所以我做了猴子会做的事情,并在上面改写为:

while (true) 
{
     Task t=ServiceAccess.GetTask();
     if (t.TaskType == 1)
     {
          DoTaskType1(t);
     } 
     else if (t.TaskType == 2)
     {
          DoTaskType2(t);
          HeavyCPUConsumerProcessor h=new HeavyCPUConsumerProcessor();
          h.DoTask(t);
     }
}

private void DoTask1(Task T)
{
    BrutalMemoryConsumerProcessor b=new BrutalMemoryConsumerProcessor();
    b.DoTask(T);
}

private void DoTask2(Task T)
{
    HeavyCPUConsumerProcessor b=new HeavyCPUConsumerProcessor();
    b.DoTask(T);
}
我的。它解决了内存泄漏问题。

因此,通过将对象创建移动到肯定会超出范围的函数中,尽管if代码块本身就是范围,但对象已被释放并被删除。

为什么?

1 个答案:

答案 0 :(得分:5)

您可能未经优化运行(在调试模式下,或附加调试器)。在这种情况下,JIT将本地生命周期延长到方法的末尾,以帮助调试。

使用单独的方法,本地人只存在于一个单独的堆栈框架中,它很快就会消失。

在没有调试器的发布模式下尝试。