Reputation: 19986
I have a .net 2.0 app that does some heavy processing, uses lots of memory, and does it some more. It takes tasks from an web service, does it's job, returns results, and repeats all that to infinity.
Main code structure can be simplified and illustrated by this
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);
}
}
Fortunatelly for me, it died after few cycles with OutOfMemoryException
somewhere in inner code. That is due to fact that both objects have been calibrated to use nearly all of RAM there is (for x86 app), and having old object instance while new one is being created is a sure way for process to snuff out.
OK, so I tried few tricks first. Namely:
GC.Collect();
at the beginning of the loop, just after while (true)
.
No Luck.
Next, I remembered old VB6 COM based days, and tried b = null;
and h = null;
inside the scope of the if
statement blocks.
No Luck again.
Combined, no dice.
Fired up a memory profiler. I didn't use it for some time so I needed to go through several pages of 'program files' to even find it. It is YourKit Profiler. Nice toy...
Anyway, after some meddling with it, it told me that references to b
and h
are staying inside local 'stack scope'. So I did something monkey would do, and rewrote above as:
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);
}
O my. It solved the memory leak issue.
So, by moving the object creation inside a function that will surely go out of scope, despite the fact that if
code block is scope in itself, object got freed and deleted.
Why?
Upvotes: 3
Views: 114
Reputation: 171246
You are probably running unoptimized (in Debug mode, or with debugger attached). In that case the JIT extends the lifetime of locals to the end of the method to help with debugging.
With separate methods, the locals do only exist in a separate stack frame which goes away quickly.
Try it in Release mode without debugger.
Upvotes: 5