The Black Box of .NET Headline Animator

The Black Box of .NET
Showing posts with label memory management. Show all posts
Showing posts with label memory management. Show all posts

Tuesday, April 17, 2012

How to determine which garbage collector is running

CodeProjectYou can determine which version of GC you're running via 2 methods:
  1. calling the System.Runtime.GCSettings.IsServerGC property
  2. attaching to the process using WinDbg and checking how many GC threads you have using the command "!sos.threads" without the quotes and (according to the below criteria)...
If you are running a Console app, WinForm app or a Windows Service, you will get the Workstation GC. Just because you are running on a Server OS doesn't mean that you will get the Server version of GC.
  • If your app is non-hosted on a multi-proc machine, you will get the Workstation GC - Concurrent by default.
  • If your app is hosted on a multi-proc machine, you will get the ServerGC by default.
The following apply to any given .NET Managed Process:

Workstation GC

  • Uni-processor machine
  • Always suspends threads
  • 1 Ephemeral GC Heap (SOH), 1 LOH GC Heap
  • Runs on thread that triggered GC
  • Thread priority is the same as the thread that triggered GC

Workstation GC - Concurrent

  • Only runs concurrent in Gen2/LOH (full collection)
  • Mutually exclusive with Server Mode
  • Slightly larger working set
  • GC Thread expires if not in use after a while
  • 1 Ephemeral GC Heap (SOH), 1 LOH GC Heap
  • Has a dedicated GC Thread
  • Thread priority is Normal

Server GC

  • Larger segment sizes
  • Faster than Workstation GC
  • Always suspends threads
  • 1 Ephemeral GC Heap (SOH) for each logical processor (this includes hyperthreaded), 1 LOH GC Heap for each logical processor (this includes hyperthreaded)
  • Has dedicated GC Threads
  • Thread priority is THREAD_PRIORITY_HIGHEST
There is only 1 Finalizer thread per managed process regardless of GC Mode. Even during a concurrent GC, managed threads are suspended (blocked) twice to do some phases of the GC.

A seldom known fact is that even if you try to set the Server mode of GC, you might not be running in Server GC; the GC ultimately determines which mode will be optimal for your app and WILL override your settings if it determines your ServerGC setting will negatively impact your application. Also, any hosted CLR app will have any manual GC settings overridden.

In CLR 4.0, things change just a little bit

  • Concurrent GC is now Background GC
  • Background GC only applies to Workstation GC
  • Old (Concurrent GC):
    • During a Full GC Allowed allocations up to end of ephemeral segment size
    • Otherwise, suspends all other threads
  • New (Background GC):
    • Allows for ephemeral GC’s simultaneously with Background GC if necessary
    • Performance is much faster
  • Server GC always blocks threads for collection of any generation

In CLR 4.5, things change just a little bit...again

  • Background Server GC
    • Server GC no longer blocks. Instead, it uses dedicated background GC threads that can run concurrently with user code - see MSDN: Background Server GC
Thus, in .NET 4.5+, all applications now have background GC available to them, regardless of which GC they use.

.NET 4.7.1 GC Improvements

.NET Framework 4.7.1 brings in changes in Garbage Collection (GC) to improve the allocation performance, especially for Large Object Heap (LOH) allocations. This is due to an architectural change to split the heap’s allocation lock into 2, for Small Object Heap (SOH) and LOH. Applications that make a lot of LOH allocations, should see a reduction in allocation lock contention, and see better performance. These improvements allow LOH allocations while Background GC (BGC) is sweeping SOH. Usually the LOH allocator waits for the whole duration of the BGC sweep process before it can satisfy requests to allocate memory. This can hinder performance. You can observe this problem in PerfView’s GCStats where there is an ‘LOH allocation pause (due to background GC) > 200 msec Events’ table. The pause reason is ‘Waiting for BGC to thread free lists’. This feature should help mitigate this problem.
Share

Friday, December 9, 2011

Debugging Tools to Diagnose a Memory Leak

Debugging and diagnosing a memory leak or an OutOfMemoryException can be a daunting and challenging task. Fortunately, there are a number of tools to help; some of these are "paid license" apps, but there are even more tools that are free. There is a little bit of irony here; IMHO, the better tools are the free ones...

Free Tools
Licensed Tools
Hope this helps!


Share

Wednesday, March 2, 2011

How do you properly implement the IDisposable pattern?

This is the first post of a series that I'll be making on memory management in .NET.  The subsequent posts will cover guidelines for working with disposable objects, when to implement IDisposable, and maybe a few others.

I am often asked how to correctly implement the IDisposable pattern. There are many posts you'll see from a Google search that try to answer this question. IMHO, the pattern that you find here is the safest and most correct implementation of the pattern according to .NET Best Practices and my experience. I am confident saying this because of my extensive experience with memory leak debugging, internals of the CLR, code reviews, and implementation of best practices at very large, well-known clients who rely on solid applications.  You will find that my provided implementation of this pattern is slightly different than that which is posted on MSDN.  IMHO, it isn't sufficient.  You have to agree that a large number of samples and examples posted on MSDN are "hacky" and don't do things the way that they should be done in the "real world".

A couple of notes on implementing the IDisposable pattern:
  1. Simply adding a Dispose() method to a class doesn't implement the pattern (just because it compiles doesn't mean it's correct).  I've seen this mistake made many, many times - it's just not a good idea.
  2. Adding the code below isn't enough - you must also explicitly declare the class inheriting from IDisposable ->  MyDisposableClass : IDisposable.  This is very important since objects creating/managing instances of your class might decide to try to cast it to IDisposable and call Dispose or use a 'using()' statement. If your class isn't explicitly declared to implement IDisposable, the cast will fail and Dispose will never be called.
  3. Just because you implement IDisposable correctly doesn't mean it will get called "magically". What I mean is that the GC never calls Dispose for you - you have to explicitly call it on your class from the owning object.  There is a common misconception that this can somehow magically happen by the GC and that it's not important that you explicitly call it "because the GC cleans up for you" (WRONG!)
  4. Implementing the IDisposable pattern correctly is tricky and can easily lead to problems if not done properly.  This is why I've provided the code below.
  5. I use a code snippet with the exact code below to properly and consistently implement the pattern correctly.
  6. There is great debate on whether or not you should null out rooted references. It certainly never hurts to do so. Nulling these out does do something before GC runs - it removes the rooted reference to that object. The GC later scans its collection of rooted references and collects those that do not have a rooted reference.

    Think of this example when it is good to do so: you have an instance of type "ClassA" - let's call it 'X'. X contains an object of type "ClassB" - let's call this 'Y'. Y implements IDisposable, thus, X should do the same to dispose of Y. Let's assume that X is in Generation 2 or the LOH and Y is in Generation 0 or 1. When Dispose() is called on X AND that implementation nulls out the reference to Y, the rooted reference to Y is immediately removed. If a GC happens for Gen 0 or Gen 1, the memory/resources for Y is cleaned up but the memory/resources for X is not since X lives in Gen 2 or the LOH.
Here is the code for properly implementing the IDisposable pattern in a base class:


#region IDisposable base-class implementation
 
//TODO remember to make this class inherit from IDisposable -> MyDisposableClass : IDisposable
 
/// <summary>
/// Gets or sets a value indicating whether this instance is disposed.
/// </summary>
/// <value>
///  <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
/// </value>
/// <remarks>Default initialization for a bool is 'false'</remarks>
private bool IsDisposed { getset; }
 
/// <summary>
/// Implementation of Dispose according to .NET Framework Design Guidelines.
/// </summary>
/// <remarks>Do not make this method virtual.
/// A derived class should not be able to override this method.
/// </remarks>
public void Dispose()
{
    Dispose(true);
 
    // This object will be cleaned up by the Dispose method.
    // Therefore, you should call GC.SupressFinalize to
    // take this object off the finalization queue 
    // and prevent finalization code for this object
    // from executing a second time.
 
    // Always use SuppressFinalize() in case a subclass
    // of this type implements a finalizer.
    GC.SuppressFinalize(this);
}
 
/// <summary>
/// Overloaded Implementation of Dispose.
/// </summary>
/// <param name="isDisposing"><c>true</c> to release both managed and unmanaged resources; 
/// <c>false</c> to release only unmanaged resources.</param>
/// <remarks>
/// <list type="bulleted">Dispose(bool isDisposing) executes in two distinct scenarios.
/// <item>If <paramref name="isDisposing"/> equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.</item>
/// <item>If <paramref name="isDisposing"/> equals <c>false</c>, the method has been called 
/// by the runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.</item></list>
/// </remarks>
protected virtual void Dispose(bool isDisposing)
{
    // TODO If you need thread safety, use a lock around these 
    // operations, as well as in your methods that use the resource.
    try
    {
        if (!this.IsDisposed)
        {
            // Explicitly set root references to null to expressly tell the GarbageCollector
            // that the resources have been disposed of and its ok to release the memory 
            // allocated for them.
            if (isDisposing)
            {
                // Release all managed resources here


                // Need to unregister/detach yourself from the events. Always make sure
                // the object is not null first before trying to unregister/detach them!
                // Failure to unregister can be a BIG source of memory leaks
                if (someDisposableObjectWithAnEventHandler != null)
                {                 
                    someDisposableObjectWithAnEventHandler.SomeEvent -= someDelegate;
                    someDisposableObjectWithAnEventHandler.Dispose();
                    someDisposableObjectWithAnEventHandler = null;
                }


                // If this is a WinForm/UI control, uncomment this code
                //if (components != null)
                //{
                //    components.Dispose();
                //}
            }
            // Release all unmanaged resources here  
            // (example)             if (someComObject != null && Marshal.IsComObject(someComObject))
            {
                Marshal.FinalReleaseComObject(someComObject);
                someComObject = null;
            }
        }
    }
    finally
    {
        this.IsDisposed = true;
    }
}

//TODO Uncomment this code if this class will contain members which are UNmanaged
///// <summary>Finalizer for MyDisposableClass</summary>
///// <remarks>This finalizer will run only if the Dispose method does not get called.
///// It gives your base class the opportunity to finalize.
///// DO NOT provide finalizers in types derived from this class.
///// All code executed within a Finalizer MUST be thread-safe!</remarks>
//  ~MyDisposableClass()
//  {
//     Dispose( false );
//  }
#endregion IDisposable base-class implementation
 
Here is the code for properly implementing the IDisposable pattern in a derived class:

#region IDisposable derived-class implementation

/// <summary>
/// Gets or sets a value indicating whether this instance is disposed.
/// </summary>
/// <value>
///  <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
/// </value>
/// <remarks>Default initialization for a bool is 'false'</remarks>
private bool IsDisposed { getset; }

/// <summary>
/// Overloaded Implementation of Dispose.
/// </summary>
/// <param name="isDisposing"><c>true</c> to release both managed and unmanaged resources; 
/// <c>false</c> to release only unmanaged resources.</param>
/// <remarks>
/// <list type="bulleted">Dispose(bool isDisposing) executes in two distinct scenarios.
/// <item>If <paramref name="isDisposing"/> equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.</item>
/// <item>If <paramref name="isDisposing"/> equals <c>false</c>, the method has been called

/// by the runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.</item></list>
/// </remarks>
protected override void Dispose(bool isDisposing)
{
    // TODO If you need thread safety, use a lock around these 
    // operations, as well as in your methods that use the resource.
    try
    {
        if (!this.IsDisposed)
        {
            // Explicitly set root references to null to expressly tell the GarbageCollector
            // that the resources have been disposed of and its ok to release the memory 
            // allocated for them.
            if (isDisposing)
            {
                // Release all managed resources here

                // Need to unregister/detach yourself from the events. Always make sure
                // the object is not null first before trying to unregister/detach them!
                // Failure to unregister can be a BIG source of memory leaks
                if (someDisposableObjectWithAnEventHandler != null)
                {                 
                    someDisposableObjectWithAnEventHandler.SomeEvent -= someDelegate;
                    someDisposableObjectWithAnEventHandler.Dispose();
                    someDisposableObjectWithAnEventHandler = null;
                }
                // If this is a WinForm/UI contrlol, uncomment this code
                //if (components != null)
                //{
                //    components.Dispose();
                //}
            }

            // Release all unmanaged resources here
 
 
            // (example)
            if (someComObject != null && Marshal.IsComObject(someComObject))
            {
                Marshal.FinalReleaseComObject(someComObject);
                someComObject = null;
            }
        }
    }
    finally
    {
        this.IsDisposed = true;

        // explicitly call the base class Dispose implementation
        base.Dispose(isDisposing);

    }
}
#endregion IDisposable derived-class implementation


Share