Turning off the garbage collector



style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"> style="mso-bidi-font-family: Tahoma">It is
not generally possible to turn off garbage collection. style="mso-spacerun: yes">  However, the garbage collector won’t run
unless “provoked.”  Garbage collection
is triggered by:


style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"> style="mso-bidi-font-family: Tahoma"> color=#000000>


style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: -0.25in; mso-layout-grid-align: none; mso-list: l0 level1 lfo1; tab-stops: list .5in"> color=#000000> style="mso-bidi-font-family: Tahoma; mso-fareast-font-family: Tahoma"> style="mso-list: Ignore">1) style="FONT: 7pt 'Times New Roman'">     
face=Tahoma>Allocation


style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: -0.25in; mso-layout-grid-align: none; mso-list: l0 level1 lfo1; tab-stops: list .5in"> color=#000000> style="mso-bidi-font-family: Tahoma; mso-fareast-font-family: Tahoma"> style="mso-list: Ignore">2) style="FONT: 7pt 'Times New Roman'">     
face=Tahoma>Explicit calls by the application to
System.GC.Collect


style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: -0.25in; mso-layout-grid-align: none; mso-list: l0 level1 lfo1; tab-stops: list .5in"> color=#000000> style="mso-bidi-font-family: Tahoma; mso-fareast-font-family: Tahoma"> style="mso-list: Ignore">3) style="FONT: 7pt 'Times New Roman'">     
face=Tahoma>Explicit calls by the application to services that implicitly
trigger a GC.  For example,
unloading an AppDomain will trigger at least one full
GC.


style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: -0.25in; mso-layout-grid-align: none; mso-list: l0 level1 lfo1; tab-stops: list .5in"> color=#000000> style="mso-bidi-font-family: Tahoma; mso-fareast-font-family: Tahoma"> style="mso-list: Ignore">4) style="FONT: 7pt 'Times New Roman'">     
face=Tahoma>On some operating systems, low memory notifications to the
application might cause the garbage collector to run. style="mso-spacerun: yes"> 
This is true of recent versions of
Windows.


style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"> style="mso-bidi-font-family: Tahoma"> style="mso-spacerun: yes">


style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"> style="mso-bidi-font-family: Tahoma"> face=Tahoma>Sometimes when developers want to turn off the garbage collector,
they really want to turn off the Finalizer thread. style="mso-spacerun: yes"> 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().


style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"> style="mso-bidi-font-family: Tahoma"> face=Tahoma> 


style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"> style="mso-bidi-font-family: Tahoma">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.


style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"> style="mso-bidi-font-family: Tahoma"> color=#000000>

Comments (7)

  1. Anonymous 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. Anonymous 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?

    davegoldstein@nospam.adelphia.net

  3. Anonymous 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.