views:

4400

answers:

14

Although I do understand the serious implications of playing with this function (or at least that's what I think), I fail to see why it's becoming one of these things that respectable programmers wouldn't ever use, even those who don't even know what it is for.

Let's say I'm developing an application where memory usage varies extremely depending on what the user is doing. The application life cycle can be divided into two main stages: editing and real-time processing. During the editing stage, suppose that billions or even trillions of objects are created; some of them small and some of them not, some may have finalizers and some may not, and suppose their lifetimes vary from a very few milliseconds to long hours. Next, the user decides to switch to the real-time stage. At this point, suppose that performance plays a fundamental role and the slightest alteration in the program's flow could bring catastrophic consequences. Object creation is then reduced to the minimum possible by using object pools and the such but then, the GC chimes in unexpectedly and throws it all away, and someone dies.

The question: In this case, wouldn't it be wise to call GC.Collect() before entering the second stage?

After all, these two stages never overlap in time with each other and all the optimization and statistics the GC could have gathered would be of little use here...

Note: As some of you have pointed out, .NET might not be the best platform for an application like this, but that's beyond the scope of this question. The intent is to clarify whether a GC.Collect() call can improve an application's overall behaviour/performance or not. We all agree that the circumstances under which you would do such a thing are extremely rare but then again, the GC tries to guess and does it perfectly well most of the time, but it's still about guessing.

Thanks.

+2  A: 

I think you are right about the scenario, but I'm not sure about the API.

Microsoft says that in such cases you should add memory pressure as a hint to the GC that it should soon perform a collection.

Sergio Acosta
Interesting, but the documentation says that AddMemoryPressure should be used when 'a small managed object allocates a large amount of UNmanaged memory'. (emphasis mine)
Robert Paulson
+8  A: 

Well, obviously you should not write code with real-time requirements in languages with non-real-time garbage collection.

In a case with well-defined stages, there is no problem with triggering the garbage-collector. But this case is extremely rare. The problem is that many developers are going to try to use this to paper-over problems in a cargo-cult style, and adding it indiscriminately will cause performance problems.

wnoise
A: 

There are situations where it's useful, but in general it should be avoided. You could compare it to GOTO, or riding a moped: you do it when you need to, but you don't tell your friends about it.

rjohnston
+8  A: 

From my experience it has never been advisable to make a call to GC.Collect() in production code. In debugging, yes, it has it's advantages to help clarify potential memory leaks. I guess my fundamental reason is that the GC has been written and optimized by programmers much smarter then I, and if I get to a point that I feel I need to call GC.Collect() it is a clue that I have gone off path somewhere. In your situation it doesn't sound like you actually have memory issues, just that you are concerned what instability the collection will bring to your process. Seeing that it will not clean out objects still in use, and that it adapts very quickly to both rising and lowering demands, I would think you will not have to worry about it.

TheZenker
A: 

Bottom line, you can profile the application and see how these additional collections affect things. I'd suggest staying away from it though unless you are going to profile. The GC is designed to take care of itself and as the runtime evolves, they may increase efficiency. You don't want a bunch of code hanging around that may muck up the works and not be able to take advantage of these improvements. There is a similar argument for using foreach instead of for, that being, that future improvements under the covers can be added to foreach and your code doesn't have to change to take advantage.

Christopher
+4  A: 

If you call GC.Collect() in production code you are essential declaring that you know more then the authors of the GC. That may be the case. However it's usually not, and therefore strongly discouraged.

Aaron Fischer
Upvoted for "this may be the case"
Seun Osewa
A: 

Although many people may say that its not feasible to call GC.Collect(), I would say otherwise.

If your application is smart enough to monitor the load its under and how much memory is available, you could call Collect() when CPU usage is low and if you need memory to be available to other applications during these times.

Sir Psycho
Why would you want/need to do this? From what you describe, this is essentially the same role as the GC itself...plus you still end up with the potential to hit GC cycles as memory pressure builds and the runtime decides there isn't enough space on the heap to allocate a new object.
Scott Dorman
@Scott, you assume that your app will be the only one on the machine. If you have a process that runs once a day on a server with many other non-.net services, would it not be prudent to clean up after its one time run?
StingyJack
+4  A: 

Calling GC.Collect() forces the CLR to do a stack walk to see if each object can be truely be released by checking references. This will affect scalability if the number of objects is high, and has also been known to trigger garbage collection too often. Trust the CLR and let the garbage collector run itself when appropriate.

RandomNoob
Not only do you cause the stack walk, but your applications main thread (and any child threads it created) are frozen so the GC **can** walk the stack. The more time your app spends in GC, the more time it spends frozen.
Scott Dorman
+3  A: 

One of the biggest reasons to call GC.Collect() is when you have just performed a significant event which creates lots of garbage, such as what you describe. Calling GC.Collect() can be a good idea here; otherwise, the GC may not understand that it was a 'one time' event.

Of course, you should profile it, and see for yourself.

TraumaPony
+32  A: 

From Rico's Blog...

Rule #1

Don't.

This is really the most important rule. It's fair to say that most usages of GC.Collect() are a bad idea and I went into that in some detail in the orginal posting so I won't repeat all that here. So let's move on to...

Rule #2

Consider calling GC.Collect() if some non-recurring event has just happened and this event is highly likely to have caused a lot of old objects to die.

A classic example of this is if you're writing a client application and you display a very large and complicated form that has a lot of data associated with it. Your user has just interacted with this form potentially creating some large objects... things like XML documents, or a large DataSet or two. When the form closes these objects are dead and so GC.Collect() will reclaim the memory associated with them...

So it sounds like this situation may fall under Rule #2, you know that there's a moment in time where a lot of old objects have died, and it's non-recurring. However, don't forget Rico's parting words.

Rule #1 should trump Rule #2 without strong evidence.

Measure, measure, measure.

Jon Norton
I'd say this is just the old thing. Nothing is really bad or dangerous if you know what you're doing and therefore know when and how to do it, as well as it side effects. Things like don't never, ever use xxxx are put there to protect the world from lousy programmers :D
Jorge Córdoba
see also http://stackoverflow.com/questions/233596/best-practice-for-forcing-garbage-collection-in-c/1472468#1472468
Ian Ringrose
+7  A: 

Well, the GC is one of those things I have a love / hate relationship with. We have broken it in the past through VistaDB and blogged about it. They have fixed it, but it takes a LONG time to get fixes from them on things like this.

The GC is complex, and a one size fits all approach is very, very hard to pull off on something this large. MS has done a fairly good job of it, but it is possible to fool the GC at times.

In general you should not add a Collect unless you know for a fact you just dumped a ton of memory and it will go to a mid life crisis if the GC doesn't get it cleaned up now.

You can screw up the entire machine with a series of bad GC.Collect statements. The need for a collect statement almost always points to a larger underlying error. The memory leak usually has to do with references and a lack of understanding to how they work. Or using of the IDisposable on objects that don't need it and putting a much higher load on the GC.

Watch closely the % of time spent in GC through the system performance counters. If you see your app using 20% or more of its time in the GC you have serious object management issues (or an abnormal usage pattern). You want to always minimize the time the GC spends because it will speed up your entire app.

It is also important to note that the GC is different on servers than workstations. I have seen a number of small difficult to track down problems with people not testing both of them (or not even aware that their are two of them).

And just to be as full in my answer as possible you should also test under Mono if you are targeting that platform as well. Since it is a totally different implementation it may experience totally different problems that the MS implementation.

Jason Short
+1  A: 

The .NET Framework itself was never designed to run in a realtime environment. If you truly need realtime processing you would either use an embedded realtime language that isn't based on .NET or use the .NET Compact Framework running on a Windows CE device.

Scott Dorman
He could be using the .Net Micro Framework, which WAS designed for real-time environments.
TraumaPony
@TraumaPony: Check the chart at the bottom of this page http://msdn.microsoft.com/en-us/embedded/bb278106.aspx: Clearly the Micro Framework was not designed for real-time environments. It was, however, designed for embedded environments (like WinCE) but with lower power requirements.
Scott Dorman
Oh, sorry, my bad.
TraumaPony
+1  A: 

What's wrong with it? The fact that you're second-guessing the garbage collector and memory allocator, which between them have a much greater idea about your application's actual memory usage at runtime than you do.

Rob
The heuristic nature of the garbage collector and the fact that they exposed this functionality to the outside world make me think of it as something that is useful if used where it needs to be. The problem is not using it but knowing how, where and when to use it.
Trap
A: 

The desire to call GC.Collect() usually is trying to cover up for mistakes you made somewhere else!

It would be better if you find where you forgot to dispose stuff you didn't need anymore.

Sam