What's new in Garbage Collector in .Net 4.0
With the introduction of background GC (applicable only for Generation 2 and improvement over concurrent GC), you can do ephemeral GCs (Generation 0 and 1) as the foreground GCs.
How it works
When the background GC is in progress, the background GC thread will check frequent safe points and see if there is any requirement for foreground GCs and if yes, then it blocks the background GC and user threads to perform foreground GCs. Once foreground GCs is done, the background and user thread is resumed. The background GC is currently available for workstation GC only.
This means that now only unusual circumstances should lead to long latency times.
Various Garbage Collectors
CLR provides two garbage collectors
- Workstation GC: designed for use by desktop applications
- Server GC: designed for use by server applications. ASP.Net loads Server GC on multiprocessor machines. On single processor machines it loads workstation GC with concurrent GC on.
We can use Garbage collection in our applications with the following options:
Workstation GC with concurrent GC off
This is designed for high throughput on single processor machines.
How it works
- A managed thread is doing allocations;
It runs out of allocations
It triggers a GC which will be running on this very thread;
- GC calls SuspendEE to suspend managed threads;
- GC does its work;
- GC calls RestartEE to restart the managed threads;
- Managed threads start running again.
Configuration: This mode can be configured by setting the following values in the web.config
<configuration>
<runtime>
<gcConcurrent enabled="false"/>
</runtime>
</configuration>
Workstation GC with concurrent GC on
This is designed for interactive applications where the response time is critical. Concurrent GC allows for shorter pause time.
How it works:
The concurrent GC pauses the main thread of the application for the short interval of time during the entire GC time frame. This helps the applications to be more responsive. Since Gen0 and Gen1 collections are very fast so concurrent GC doesnot work for these generations. It makes sense to make concurrent GC for generation 2
Server GC
In this case separate GC thread and a separated heap for each CPU is created. GC happens on these threads instead of on the allocating thread. The flow looks like this:
- A managed thread is doing allocations;
- It runs out of allocations on the heap its allocating on;
- It signals an event to wake the GC threads to do a GC and waits for it to finish;
- GC threads run, finish with the GC and signal an event that says GC is complete (When GC is in progress, all managed threads are suspended just like in Workstation GC);
- Managed threads start running again.
Configuration: This mode can be configured by setting the following values in the web.config
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
Important Points:
Concurrent GC is available only for Workstation GC. That means Server GC is always blocking GC.
Concurrent GC is only for the full garbage collection. Generation 0 and Generation 1 GCs are always blocking GCs.
Garbage Collection Overview
Garbage collector in .Net reclaims the memory of unused resources.
It is performed in three different generations. All the new objects that we create fall under the category of Generation 0. Garbage collector collects the unused objects from Generation 0 first before it goes to Generation 1 and then 2. Everytime GC runs it advances the generation of the object (which survived from Garbage collection) to next level till the Generation 2.
.Net System.GC class implements several methods that can be used by programmers. Here is the brief about each of the methods:
- System.GC.Collect: This method forces garbage collection. This method should not be called explicitly to start garbage collection as it adversely effects the performance of the application.
- System.GC.WaitForPendingFinalizers: This method suspends the execution of the current thread until the finalization thread has emptied the finalization queue. As with GC.Collect this method should be not be called.
- System.GC.KeepAlive: This method is used to prevent an object to be garbage collected prematurely. This could happen if your managed code is not using the object however unmanaged code is using the object.
- System.GC.SuppressFinalize: This prevents the finalizer being called for a specified object. Use this method when you implement the dispose pattern.
A short note on Finalization
.Net garbage collection mechanism keeps track of the objects life time using the strong and weak references. However when it comes to unmanaged resources like file, network connections it doesnot maintain their life time. You need to write the code to free the unmanaged resources. Net provides Object.Finalize method that can be used to free unmanaged resources. Whenever a new object, having a Finalize method, is allocated on the heap a pointer to the object is placed in an internal data structure called Finalization queue. When the object is not reachable (means ready for garbage collection), GC removes the object from Finalization Queue and put that in another internal data structure called Freachable Queue. A special runtime thread empties the Freachable queue by executing the Finalize method.
The next time garbage collector runs it sees that the finalized objects are truly garbage (means their finalize method has been executed) and then the memory of those object is freed.
It is recommended to avoid using Finalize method unless required as it delays the garbage collection of those objects to the next time when GC runs.
Use Dispose Pattern
The Dispose pattern defines the way we should implement finalizer functionality on all managed classes that maintain resources that the caller must be allowed to explicitly release. To implement the Dispose pattern, do the following:
- Create a class that derives from IDisposable.
- Add a private member variable to track whether IDisposable.Dispose has already been called. Clients should be allowed to call the method multiple times without generating an exception. If another method on the class is called after a call to Dispose, you should throw an ObjectDisposedException.
- Implement a protected
virtual
void override of the Dispose method that accepts a single bool parameter. This method contains common cleanup code that is called either when the client explicitly calls IDisposable.Dispose or when the finalizer runs. The bool parameter is used to indicate whether the cleanup is being performed as a result of a client call to IDisposable.Dispose or as a result of finalization. - Implement the IDisposable.Dispose method that accepts no parameters. This method is called by clients to explicitly force the release of resources. Check whether Dispose has been called before; if it has not been called, call Dispose(true) and then prevent finalization by calling GC.SuppressFinalize(this). Finalization is no longer needed because the client has explicitly forced a release of resources.
- Create a finalizer, by using destructor syntax. In the finalizer, call Dispose(false).
Code
public sealed class MyClass: IDisposable
{
// Variable to track if Dispose has been called
private bool disposed = false;
// Implement the IDisposable.Dispose() method
public void Dispose(){
// Check if Dispose has already been called
if (!disposed)
{
// Call the overridden Dispose method that contains common cleanup code
// Pass true to indicate that it is called from Dispose
Dispose(true);
// Prevent subsequent finalization of this object. This is not needed
// because managed and unmanaged resources have been explicitly released
GC.SuppressFinalize(this);
}
}
// Implement a finalizer by using destructor style syntax
~MyClass() {
// Call the overridden Dispose method that contains common cleanup code
// Pass false to indicate the it is not called from Dispose
Dispose(false);
}
// Implement the override Dispose method that will contain common
// cleanup functionality
protected virtual void Dispose(bool disposing){
if(disposing){
// Dispose time code
. . .
}
// Finalize time code
. . .
}
…}
Passing true to the protected Dispose method ensures that dispose specific code is called. Passing false skips the Dispose specific code. The Dispose(bool) method can be called directly by your class or indirectly by the client.
If you reference any static variables or methods in your finalize-time Dispose code, make sure you check the Environment.HasShutdownStarted property. If your object is thread safe, be sure to take whatever locks are necessary for cleanup.
Use the HasShutdownStarted property in an object's Dispose method to determine whether the CLR is shutting down or the application domain is unloading. If that is the case, you cannot reliably access any object that has a finalization method and is referenced by a static field.
References:
http://blogs.msdn.com/maoni/archive/2004/09/25/234273.aspx
http://msdn.microsoft.com/en-us/library/ms998549.aspx#scalenetchapt06_topic5
http://msdn.microsoft.com/en-us/library/cc713687%28VS.100%29.aspx
http://blogs.msdn.com/maoni/archive/2008/11/19/so-what-s-new-in-the-clr-4-0-gc.aspx