Take the 2-minute tour ×

In my experience it seems that most people will tell you that it is unwise to force a garbage collection but in some cases where you are working with large objects that don't always get collected in the 0 generation but where memory is an issue, is it ok to force the collect? Is there a best practice out there for doing so?

share|improve this question

15 Answers 15

up vote 85 down vote accepted

The best practise is to not force a garbage collection.

According to MSDN:

"It is possible to force garbage collection by calling Collect, but most of the time, this should be avoided because it may create performance issues. "

However, if you can reliably test your code to confirm that calling Collect() won't have a negative impact then go ahead...

Just try to make sure objects are cleaned up when you no longer need them. If you have custom objects, look at using the "using statement" and the IDisposable interface.

This link has some good practical advice with regards to freeing up memory / garbage collection etc:


share|improve this answer
Also, you can set different LatencyMode's msdn.microsoft.com/en-us/library/bb384202.aspx –  David d C e Freitas Jul 8 '11 at 15:18
If your objects point to unmanaged memory, you can let the garbage collector know through the GC.AddMemoryPressure Api (msdn.microsoft.com/en-us/library/…). This gives the garbage collector more information about your system without interfering with the collection algorithms. –  Govert Feb 1 '12 at 18:51
+1: * look at using the "using statement" and the IDisposable interface.* I wouldn't even consider forcing except as a last resort - good advice (read as 'disclaimer'). I am, however, forcing collection in a unit test to simulate losing an active reference in a back-end operation - ultimately throwing a TargetOfInvocationNullException. –  IAbstract Apr 1 '12 at 15:30

Look at it this way - is it more efficient to throw out the kitchen garbage when the garbage can is at 10% or let it fill up before taking it out?

By not letting it fill up, you are wasting your time walking to and from the garbage bin outside. This analogous to what happens when the GC thread runs - all the managed threads are suspended while it is running. And If I am not mistaken, the GC thread can be shared among multiple AppDomains, so garbage collection affects all of them.

Of course, you might encounter a situation where you won't be adding anything to the garbage can anytime soon - say, if you're going to take a vacation. Then, it would be a good idea to throw out the trash before going out.

This MIGHT be one time that forcing a GC can help - if your program idles, the memory in use is not garbage-collected because there are no allocations.

share|improve this answer
If you had a baby that would die if you left it for more than a minute, and you only ever had a minute to handle the garbage, then you'd want to do a little each time instead of all at once. Unfortunately, the GC::Collect() method isn't any quicker the more often you call it. So for a realtime engine, if you can't just use the dispose mechanism and let the GC pool your data, then you shouldn't use a managed system -- as per my answer (probably below this one, lol). –  Dedic Feb 1 '12 at 20:46
In my case, I'm running a A* (shortest path) algorith REPEATEDLY to performance tune it... which, in production, will only be run once (on each "map"). So I want the GC to be done before each iteration, outside of my "performance measured block", because I feel that more closely models the situation in production, in which the GC could/should be forced after navigating each "map". –  corlettk Sep 12 '12 at 6:48
Calling GC before the measured block actually does not models the situation in production, because in production the GC will be done in unpredictable times. To mitigate that, you should take a long measurement that will include several GC executions, and factor the peaks during GC into your analysis and statistics. –  Ran Dec 18 '12 at 23:03

I think the example given by Rico Mariani was good: it may be appropriate to trigger a GC if there is a significant change in the application's state. For example, in a document editor it may be OK to trigger a GC when a document is closed.

share|improve this answer
Or just before opening a large contiguous object that has shown a history of failure and presents no efficient resolution for increasing its granularity. –  crokusek Jun 25 '13 at 0:05

The best practise is to not force a garbage collection in most cases. (Every system I have worked on that had forced garbage collections, had underlining problems that if solved would have removed the need to forced the garbage collection, and speeded the system up greatly.)

There are a few cases when you know more about memory usage then the garbage collector does. This is unlikely to be true in a multi user application, or a service that is responding to more then one request at a time.

However in some batch type processing you do know more then the GC. E.g. consider an application that.

  • Is given a list of file names on the command line
  • Processes a single file then write the result out to a results file.
  • While processing the file, creates a lot of interlinked objects that can not be collected until the processing of the file have complete (e.g. a parse tree)
  • Does not keep match state between the files it has processed.

You may be able to make a case (after careful) testing that you should force a full garbage collection after you have process each file.

Another cases is a service that wakes up every few minutes to process some items, and does not keep any state while it’s asleep. Then forcing a full collection just before going to sleep may be worthwhile.

The only time I would consider forcing a collection is when I know that a lot of object had been created recently and very few objects are currently referenced.

I would rather have a garbage collection API when I could give it hints about this type of thing without having to force a GC my self.

See also "Rico Mariani's Performance Tidbits"

share|improve this answer

I've learned to not try to outsmart the compiler. With that said, I just stick to using using keyword when dealing with unmanaged resources like file I/O or database connections.

share|improve this answer
compiler? what does the compiler have to do with GC? :) –  KristoferA Sep 24 '09 at 15:36
Nothing, it only compiles and optimizes code. And this definitely has nothing to do with the CLR... or .NET even. –  Kon Oct 17 '09 at 16:28
Objects occupying lots of memory, like very big images, can end up not getting garbage collected, unless you explicitly garbage collect them. I think this (large objects) was the OP's issue, more or less. –  code4life Feb 16 '13 at 17:05
Wrapping it in a using will ensure that it's scheduled for GC once it's out of using scope. Unless the computer explodes, that memory will most likely be cleaned up. –  Kon Feb 17 '13 at 2:30

There are few general guidelines in programming that are absolute. Half the time, when somebody says 'you're doing it wrong', they're just spouting a certain amount of dogma. In C, it used to be fear of things like self-modifying code or threads, in GC languages it is forcing the GC or alternatively preventing the GC from running.

As is the case with most guidelines and good rules of thumb (and good design practices), there are rare occasions where it does make sense to work around the established norm. You do have to be very sure you understand the case, that your case really requires the abrogation of common practice, and that you understand the risks and side-effects you can cause. But there are such cases.

Programming problems are widely varied and require a flexible approach. I have seen cases where it makes sense to block GC in garbage collected languages and places where it makes sense to trigger it rather than waiting for it to occur naturally. 95% of the time, either of these would be a signpost of not having approached the problem right. But 1 time in 20, there probably is a valid case to be made for it.

share|improve this answer

I think you already listed the best practice and that is NOT to use it unless REALLY necessary. I would strongly recommend looking at your code in more detail, using profiling tools potentially if needed to answer these questions first.

  1. Do you have something in your code that is declaring items at a larger scope than needed
  2. Is the memory usage really too high
  3. Compare performance before and after using GC.Collect() to see if it really helps.
share|improve this answer

One case I recently encountered that required manual calls to GC.Collect() was when working with large C++ objects that were wrapped in tiny managed C++ objects, which in turn were accessed from C#.

The garbage collector never got called because the amount of managed memory used was negligible, but the amount of unmanaged memory used was huge. Manually calling Dispose() on the objects would require that I keep track of when objects are no longer needed myself, whereas calling GC.Collect() will clean up any objects that are no longer referred.....

share|improve this answer
A better way to solve this is by calling GC.AddMemoryPressure (ApproximateSizeOfUnmanagedResource) in the constructor and later GC.RemoveMemoryPressure(addedSize) in the finalizer. This way the garbage collector will run automatically, taking into account the size of the unmanaged structures that could be collected. stackoverflow.com/questions/1149181/… –  HugoRune Jan 21 '13 at 9:57
And an even better way to solve the problem is to actually call Dispose(), which you are supposed to do anyway. –  fabspro Mar 14 at 14:12

Not sure if it is a best practice, but when working with large amounts of images in a loop (i.e. creating and disposing a lot of Graphics/Image/Bitmap objects), i regularly let the GC.Collect.

I think I read somewhere that the GC only runs when the program is (mostly) idle, and not in the middle of a intensive loop, so that could look like an area where manual GC could make sense.

share|improve this answer
Are you sure that you need this? The GC will collect if it needs memory, even if your code is not idle. –  Konrad Rudolph Oct 24 '08 at 13:56
Not sure how it is in .net 3.5 SP1 now, but previously (1.1 and i believe i tested against 2.0) it did make a difference in memory usage. The GC will of course always collect when needed, but you might still end up wasting 100 Megs of RAM when you only need 20. Would need a few´more tests though –  Michael Stum Oct 24 '08 at 14:06
GC is triggered on memory allocation when generation 0 reaches a certain threshold (for example 1MB), not when "something is idle". Otherwise you could end up with OutOfMemoryException in a loop by simply allocating and immediately discarding objects. –  liggett78 Oct 24 '08 at 14:11
the 100megs of RAM isn't wasted if no other processes needed it. It's giving you a nice performance boost :-P –  Orion Edwards Nov 2 '08 at 2:40

Large objects are allocated on LOH (large object heap), not on gen 0. If you're saying that they don't get garbage-collected with gen 0, you're right. I believe they are collected only when the full GC cycle (generations 0, 1 and 2) happens.

That being said, I believe on the other side GC will adjust and collect memory more aggressively when you work with large objects and the memory pressure is going up.

It is hard to say whether to collect or not and in which circumstances. I used to do GC.Collect() after disposing of dialog windows/forms with numerous controls etc. (because by the time the form and its controls end up in gen 2 due to creating many instances of business objects/loading much data - no large objects obviously), but actually didn't notice any positive or negative effects in the long term by doing so.

share|improve this answer

Suppose your program doesn't have memory leakage, objects accumulates and cannot be GC-ed in Gen 0 because: 1) They are referenced for long time so get into Gen1 & Gen2; 2) They are large objects (>80K) so get into LOH (Large Object Heap). And LOH doesn't do compacting as in Gen0, Gen1 & Gen2.

Check the performance counter of ".NET Memory" can you can see that the 1) problem is really not a problem. Generally, every 10 Gen0 GC will trigger 1 Gen1 GC, and every 10 Gen1 GC will trigger 1 Gen2 GC. Theoretically, GC1 & GC2 can never be GC-ed if there is no pressure on GC0 (if the program memory usage is really wired). It never happens to me.

For problem 2), you can check ".NET Memory" performance counter to verify whether LOH is getting bloated. If it is really a issue to your problem, perhaps you can create a large-object-pool as this blog suggests http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx.

share|improve this answer

I would like to add that: Calling GC.Collect() (+ WaitForPendingFinalizers()) is one part of the story. As rightly mentioned by others, GC.COllect() is non-deterministic collection and is left to the discretion of the GC itself (CLR). Even if you add a call to WaitForPendingFinalizers, it may not be deterministic. Take the code from this msdn link and run the code with the object loop iteration as 1 or 2. You will find what non-deterministic means (set a break point in the object's destructor). Precisely, the destructor is not called when there were just 1 (or 2) lingering objects by Wait..().[Citation reqd.]

If your code is dealing with unmanaged resources (ex: external file handles), you must implement destructors (or finalizers).

Here is an interesting example:

Note: If you have already tried the above example from MSDN, the following code is going to clear the air.

class Program
    static void Main(string[] args)
            SomePublisher publisher = new SomePublisher();

                SomeSubscriber subscriber = new SomeSubscriber(publisher);
                subscriber = null;




    public class SomePublisher
        public event EventHandler SomeEvent;

    public class SomeSubscriber
        public static int Count;

        public SomeSubscriber(SomePublisher publisher)
            publisher.SomeEvent += new EventHandler(publisher_SomeEvent);


        private void publisher_SomeEvent(object sender, EventArgs e)
            // TODO: something
            string stub = "";

I suggest, first analyze what the output could be and then run and then read the reason below:

{The destructor is only implicitly called once the program ends. } In order to deterministically clean the object, one must implement IDisposable and make an explicit call to Dispose(). That's the essence! :)

share|improve this answer

One more thing, triggering GC Collect explicitly may NOT improve your program's performance. It is quite possible to make it worse.

The .NET GC is well designed and tuned to be adaptive, which means it can adjust GC0/1/2 threshold according to the "habit" of your program memory usage. So, it will be adapted to your program after some time running. Once you invoke GC.Collect explicitly, the thresholds will be reset! And the .NET has to spent time to adapt to your program's "habit" again.

My suggestion is always trust .NET GC. Any memory problem surfaces, check ".NET Memory" performance counter and diagnose my own code.

share|improve this answer
I think it's better that you merge this answer with your previous answer. –  Salamander2007 Nov 6 '08 at 4:48


IMHO, this is similar to saying "If you can prove that your program will never have any bugs in the future, then go ahead..."

In all seriousness, forcing the GC is useful for debugging/testing purposes. If you feel like you need to do it at any other times, then either you are mistaken, or your program has been built wrong. Either way, the solution is not forcing the GC...

share|improve this answer

Not sure if it is a best practice...

Suggestion: do not implement this or anything when unsure. Reevaluate when facts are known, then perform before/after performance tests to verify.

share|improve this answer

Your Answer


