views:

265

answers:

7

Ok this is potentially a noob question but here goes.

Is it possible to "outrun" the garbage collector?

The reason I ask is because I have a recursive method that gets run several times during some event in my application (by several I mean around 60 times per second and the event goes on for an indefinite amount of time, even minutes). The problem is that in each loop of the recursive method, I create a fairly complex object (TreeViewItem with some mods we need for the project AND another complex object that works as the DataContext for the TreeViewItem), so my concern is that these TreeViewItems stay in the heap when the recursive method runs, so when the garbage collector kicks in, it doesn't clean them; and possibly, the next time the recursive method starts, it stacks some more TreeViewItem, and the garbage collector never catches up.

The problem is that we have a memory leak, and we're looking for the culprit.

Any help really appretiated

+4  A: 

No, you can't 'outrun' the garbage collector, it will interrupt your code if necessary. The details depend a bit on whether you're running as a server or not.

The bigger question is: Why do you think you have a memory leak? And that's where you start searching for the reason.

And please don't call GC.Collect(), it will do more harm than good.


Addition 1

The main 'problem' that can happen with memory management is keeping references around you don't need anymore. Normally this goes quit natural with the flow, as local variables are cleared when a method returns. But you should look for references that are setup between objects. One notable example are eventhandlers, if your objects subscribe to an event then that subscription contains a reference to the subscribing object. Make sure you clear those when no longer needed.

Henk Holterman
Every time this method runs, the memory keeps going up and up, the programmer who found it was able to reach an OutOfMemoryException after getting up to 1.5 GB (in half an hour).
Carlo
I think that you should revise your post as well. You say that you are worried about these objects staying on the stack, but they are allocated on the heap, not the stack, and I am sure that your stack comes nowhere nere 1.5 GB's.
Ed Swangren
Some things you need to look for are using disposable objects inside your loop without disposing of them afterwards (should be done in a using block) and performing a lot of string concatenation inside the loop. It would help to possibly see some code as well.
Scott Dorman
You're right I usually mix those up. Thanks.
Carlo
+1  A: 

Do garbage collectors look at stacks?

The ones I use are only concerned about heaps, and if ncessary can stop all threads while they shuffle the heap around.

What's your evidence that you have a leak as opposed to just too much stuff in general? Sometimes stacks grow in one direction and heaps in the other - Out Of Memory doesn't imply "leak".

djna
Yes this issue sounds like running out of memory, not any sort of garbage collection issue. Reminds me of my Othello AI...
The objects are in the GC heap, but their root is on the stack. Since they are active, they can't be GC'd.
Michael
A: 

I don't believe it is; the garbage collector is generally implicitly tied into memory allocation; and so can get invoked when memory is allocated; however I'm no expert in how the .Net framework does garbage collection.

The most likely cause of your memory leak (in managed code) is Object(s) which you have finished with; but still have a reference to.

Dave Rigby
A: 

The GC is only going to run when it detects a need to run. In other words, when it detects that there is enough memory pressure to require a collection cycle, which generally (although this isn't the only reason) is when there isn't enough heap space to perform the next allocation.

Some things you need to look for are using disposable objects inside your loop without disposing of them afterwards (should be done in a using block) and performing a lot of string concatenation inside the loop.

You need to ensure that you are properly ending the recursion and ascending back up the call-stack. Also, do you need to have the DataContext set for each TreeViewItem? Is this something that can be set once at the TreeView and let the TreeViewItems walk the hierarchy to find the appropriate DataContext?

Scott Dorman
I'm sorry it's the WPF object that represents a tree node in a TreeView.
Carlo
+5  A: 

No, you can't make the garbage collector leak by overloading it.

The way that the garbage collector works actually makes it handle situations like yours rather well.

If you remove a reference to a large complex of objects, it will not collect the objects one at a time. It sees that none of the objects have any active references any more and it will collect the whole bunch of objects at once.

Most objects are short lived, so the garbage collector is built to handle that efficiently. If you for example have filled the first generation heap, and 90% of the objects are to be collected, the garbage collector doesn't remove the 90%. Instead it moves the 10% to the next generation and simply wipes the first generation.

If the garbage collector still finds itself with a lot of work to do, it will just do it, and you will have to wait for it. It freezes your threads while it's working, and they simply won't run until the garbage collector is done.

Guffa
I liked this answer, very explanatory. Thanks!
Carlo
A: 

If this is your problem:

Every time this method runs, the memory keeps going up and up, the programmer who found it was able to reach an OutOfMemoryException after getting up to 1.5 GB (in half an hour).

Then I'd recommend stripping functions out of your loop a layer at a time (in layers that make sense) until you get to something that doesn't lose memory. Then add functions back in little teeny-tiny pieces until you identify the one causing the leak.

Beth
A: 

You can't "outrun" the garbage collector, but it is possible to stress it badly. This usually shows up as high CPU usage, rather than the GC not cleaning up large chunks of memory that need to be cleaned up.

If you are building up to an OutOfMemoryException over half an hour, then it certainly isn't the case that you're overloading the garbage collector. It's much more likely, as others have said, that references to new objects you're creating are staying alive as your application runs. This doesn't mean you should just set your timer loop up to null everything out, you need to identify the cause of the retained references and what action you should be taking to tidy things up at the end of a piece of work that you're not currently doing.

The best tool for this kind of work is a memory profiler. They will analyse living objects and the references to them in your application and allow you to find out what objects you think should be collected are still alive, and why. This will be the cause of your leak.

The GC will identify what objects in your application are guaranteed to be alive (gc roots), such as static variables, local variables, etc. It will then follow what the roots reference to find every currently living object. The rest is garbage. This is a very simplified way of putting it, but it shows that what you need to find is what root path(s) lead to the objects you're creating, and break them at the appropriate point.

Although you say you are not using events yourself, it's very likely that some control that is alive the whole time is subscribing to events on your new objects, or otherwise keeping them in a list somewhere.

I have used the Scitech memory profiler a lot before and found it to be very helpful. There are also other tools - dotTrace, Ants memory profiler, and lots more. I have used a fair few of them and find that Scitech's profiler gets to the point best. They probably all have trial periods! :)

Niall Connaughton