我有一个.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。好玩具......
无论如何,在经过一些干预之后,它告诉我对b
和h
的引用仍留在本地“堆栈范围”内。所以我做了猴子会做的事情,并在上面改写为:
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
代码块本身就是范围,但对象已被释放并被删除。
为什么?
答案 0 :(得分:5)
您可能未经优化运行(在调试模式下,或附加调试器)。在这种情况下,JIT将本地生命周期延长到方法的末尾,以帮助调试。
使用单独的方法,本地人只存在于一个单独的堆栈框架中,它很快就会消失。
在没有调试器的发布模式下尝试。