Turning off the garbage collector

It is not generally possible to turn off garbage collection. However, the garbage collector won’t run unless “provoked.” Garbage collection is triggered by:

  1. Allocation
  2. Explicit calls by the application to System.GC.Collect
  3. Explicit calls by the application to services that implicitly trigger a GC. For example, unloading an AppDomain will trigger at least one full GC.
  4. On some operating systems, low memory notifications to the application might cause the garbage collector to run. This is true of recent versions of Windows.

Sometimes when developers want to turn off the garbage collector, they really want to turn off the Finalizer thread. This thread runs asynchronously to the application and at a high priority. If the application has a time window where it doesn’t want the Finalizer thread to intrude, one approach is to drain the finalizer queue before starting this time-critical operation. The queue can be drained by calling GC.WaitForPendingFinalizers().

Of course, this doesn’t actually turn off finalization. But it does create a window where finalization is far less likely to intrude on your application.

Comments (7)

  1. Chris Brumme says:

    Within Microsoft, I occasionally run into teams who are triggering the garbage collector so they can recover a particular instance.

    This is a bad idea.

    The GC’s purpose is to efficiently manage resources. Because of this, GC.Collect & GC.WaitForPendingFinalizers are non-deterministic.

    The way to achieve determinism in an application is through IDisposable and similar APIs, not by jiggling the GC.

    One can never predict when the last reference to an object has been released. Storing a reference to null might be eliminated by the JIT as a dead store. Depending on register allocation, the lifetime of your reference might be extended to the end of a method. Depending on how aggressively the JIT is inlining, the lifetime of your reference might be extended to the end of some enclosing method.

    We should not confuse the lifetime of an object’s memory with the semantics we try to achieve inside a Finalize method. And we should never trigger expensive GCs and draining of the finalizer queue when we are trying to have an impact on a particular object.

    So what is a legitimate use of GC.Collect and GC.WaitForPendingFinalizers? It is to have a statistical effect on the state of the GC heap. If you have closed a bunch of windows, or finished a long-running request, or released a ton of cached objects, then calling GC.Collect() might make good sense from a statistical point of view. But there are no guarantees on whether a particular object will collect.

    Along the same lines, a HandleCollector might track the number of outstanding instances of a scarce resource. If a client requests a new instance and some threshold has been reached, the HandleCollector can trigger a GC and WaitForPendingFinalizers – hoping to reclaim some resources. But it isn’t making these calls with a goal of reclaiming a particular instance.

    If you rely on GC.Collect / WaitForPendingFinalizers to recover a particular instance, your app will certainly be broken as we pursue more aggressive code generation and GC techniques. (Or perhaps it will just be broken during debugging, or when you run on a non-X86 CPU, or even a machine with more memory).

  2. David Goldstein says:

    This was a debate I started at Code Project…

    if you explicitly collect, won’t you artificially promote short-lived gen0 objects into further generations?


  3. Chris Brumme says:

    Explicitly collecting is generally a bad idea. Promotion of short-lived objects into older generations is indeed one of the problems this will cause.

Skip to main content