【发布时间】:2013-09-03 15:02:15
【问题描述】:
我有一个 .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 的日子,并在 if 语句块的范围内尝试了 b = null; 和 h = null;。
又没有运气了。
组合,没有骰子。
启动了内存分析器。我有一段时间没有使用它,所以我需要浏览几页“程序文件”才能找到它。它是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 代码块本身就是范围,但通过将对象创建移动到肯定会超出范围的函数中,对象被释放和删除。
为什么?
【问题讨论】:
标签: c# .net memory-leaks .net-2.0