Monday, April 28, 2008

When does the .NET Compact Framework Garbage Collector run



Other than the exact when part this post applies equally for the desktop portion.

Disclaimer: This post is mainly indicative. When the GC runs is an implementation detail and shouldn't be relied on. This is not part of any contract or specification and may (most probably will) change.

The ECMA specification for Garbage Collection is intentionally vague about when an object will be collected (or freed up). The memory management cycle mentioned in the spec is as follows

1. When the object is created, memory is allocated for it, the constructor is run, and the object is considered live.
2. If no part of the object can be accessed by any possible continuation of execution, other than the running of finalizers, the object is considered no longer in use and it becomes eligible for finalization. [Note: Implementations might choose to analyze code to determine which references to an object can be used in the future. For instance, if a local variable that is in scope is the only existing reference to an object, but that local variable is never referred to in any possible continuation of execution from the current execution point in the procedure, an implementation might (but is not required to) treat the object as no longer in use. end note]
3. Once the object is eligible for finalization, at some unspecified later time the finalizer (§17.12) (if any) for the object is run. Unless overridden by explicit calls, the finalizer for the object is run once only.
4. Once the finalizer for an object is run, if that object, or any part of it, cannot be accessed by any possible continuation of execution, including the running of finalizers, the object is considered inaccessible and the object becomes eligible for collection.
5. Finally, at some time after the object becomes eligible for collection, the garbage collector frees the memory associated with that object.

As you can see the specification doesn't even need an implementation to do code analysis to figure out garbage. It can simply use scoping rules (used anyway by the compiler to detect valid variable usage) for garbage detection. The specification also doesn't specify eventually when the objects are collected. The only need is that it is finalized and freed unspecified time later than the time when it goes out of use. This convenient open statement lets each GC implementers to choose whatever they deem fit for the purpose. Since even thread is not specified a concurrent GC or a non-concurrent GC can be used.

However, everyone wants to know exactly when their platform's GC is run. Here goes the non-exhaustive list for the .NET Compact Framework's Garbage Collector

  1. Out of memory condition:
    When the system fails to allocate or re-allocate memory a full GC is run to free up as much as possible and then allocation is re-attempted once more before giving up
  2. After some significant allocation:
    If one megabyte of memory is allocated since the last garbage collection then GC is fired.
  3. Failure of allocating some native resources:
    Internally .NET uses various native resources. Some native resource allocation can fail due to memory issues and GC is run before re-attempting
  4. Profiler:
    Profiler APIs build into the framework can force a GC
  5. Forced GC:
    System.GC class is provided in the BCL to force a collection

Obviously there can be small differences across various platforms on which .NET CF is implemented. However, the differences are small enough to ignore for this discussion.

Even though this list seems small it works pretty well across disparate systems like XBox and Windows Mobile. In the next post I'll try to get into why "production user code should never do a forced GC". I know that statement is a bit controversial (at least it got so in an internal thread).

No comments: