All posts by admin

Growing IDisposable Guided By Tests

My previous post looked at the limitations of the .NET Garbage Collection process. The right way to mitigate these limitations is by allowing an objects owner to call Dispose() to release resources on demand rather than having to wait for the Finalization Queue to run. In this post I will grow a worked example that conforms to the basic design pattern for implementing Dispose. Tests will drive the design of the sample class to ensure that:

  • when the Finalizer is called it releases all unmanaged resources
  • when the Finalizer is called it does NOT Dispose its managed resources (remember that the order of finalization is not guaranteed, so the managed resource may already have been finalized)
  • when Dispose() is called all unmanaged resources are released
  • when Dispose() is called all managed Disposable objects are Disposed

To conform to the IDisposable design pattern, the sample class must also:

  • implement IDisposable
  • provide a protected virtual Dispose(bool disposing) method
  • the Dispose() method must call Dispose(true)
  • the Dispose() method must suppress finalization
  • if a finalizer is needed, it must call Dispose(false)
  • handle Dispose() being called multiple times
  • throw an ObjectDisposedException in any other public method tries to access disposed objects

For these tests I will use xUnit and FluentAssertions.

Sample class

We begin with a sample class that owns an unmanaged resource (in this case a block of memory allocated from the unmanaged COM task allocator) as well as a disposable managed resource (in this case a MemoryStream).

public class ResourceOwner
{
    protected IntPtr AnUnmanagedResource = Marshal.StringToCoTaskMemAuto("Foo");
    protected MemoryStream ADisposableResource = new MemoryStream();
}
Test 1: When the Finalizer is called it releases all unmanaged resources

Ideally the test would simply call the Finalizer and then check that the unmanaged resource has been released. Unfortunately there is no way to call the Finalizer. The best we can do is use a testing strategy called “subclass to test“, create a method to mimic the Finalizer and visually ensure that it and the Finalizer are always in sync. Terrible, I know, but I can’t think of any other way. DI won’t work because if we inject the finalizable resources then the ResourceOwner won’t own them so shouldn’t dispose of them.  Subclassing also allows us to spy on the non-public resources owned by the base class. It is important to remember that the subclass is part of the test suite, not the system under test, so it will not be test-driven (but we can trust it anyway). The first test looks like this:

 [Fact]
public void ReleasesUnmanagedResourcesWhenFinalized()
{
    var spy = new ResourceSpy();
    spy.MimicFinalizer();
    spy.UnmanagedResourcesHaveBeenReleased.Should().BeTrue();
}

To make it compile we add:

 public class ResourceSpy : ResourceOwner
{
    public void MimicFinalizer(){}
 
    public bool UnmanagedResourcesHaveBeenReleased
    {
    get
        {
            var referencedString = Marshal.PtrToStringAuto(AnUnmanagedResource);
            return referencedString != "Foo";
        }
    }
}

The test fails. To make it pass we release the unmanaged resources – we call FreeCoTaskMem as advised here:

public class ResourceSpy : ResourceOwner
{
    public void MimicFinalizer()
    {
        Marshal.FreeCoTaskMem(AnUnmanagedResource);
    }
    ...
}

… and synchronize the Finalizer:

public class ResourceOwner
{
    ...
    ~ResourceOwner()
    {
        Marshal.FreeCoTaskMem(AnUnmanagedResource);
    }
}

Now the test passes, but then the test suite crashes! The reason is that FreeCoTaskMem is being called twice – once during the test by MimicFinalizer and then when the GC calls the actual finalizer. In the real world the finalizer only ever gets called once so this doesn’t need to be handled by the ResourceOwner, rather we suppress the finalizer at the end of the test:

[Fact]
public void ReleasesUnmanagedResourcesWhenFinalized()
{
    var spy = new ResourceSpy();
    spy.MimicFinalizer();
    spy.UnmanagedResourcesHaveBeenReleased.Should().BeTrue();
    GC.SuppressFinalize(spy);
}

The test passes and the test suite does not crash.

.NET Garbage Collection Primer

In .NET, running applications store their state (data) in a heap (specifically objects <85k on the Small Object Heap (SOH) while larger objects are usually written to the Large Object Heap). When those objects are no longer required by the application, they need to be removed to make space for new objects. .NET deals with this through a process called Garbage Collection (GC).

Simplified Model

The simplified model of the Garbage Collection process is as follows:

  1. Pause application execution
  2. Starting at the root of the application, follow all reference paths to discover which objects are reachable by the application. The root includes the stack, global & static objects, as well as the finalization references. Each object is only visited once to avoid issues with circular references.
  3. Remove all unreachable objects from the heap and free up the space.
  4. Compact the SOH.
  5. Resume application execution

Generations

Given that GC interrupts application execution, the shorter the GC runs, the better the user experience. One way to achieve this is to use a generational garbage collection algorithm. The idea behind it is that if an object has lived for a while it is probably used widely within the application and chances are that it will still be needed for a while longer. Usually there are far more short-lived objects in an application than long-lived ones, these being created within a small scope for a single task, so most young objects tend to be short-lived. In other words, the longer an object has lived, the longer it is likely to be needed, so cleaning young objects tends to be more fruitful than looking for older object to clean.

One way to track the age of an object is through Generations. (I capitalize Generations to indicate the special meaning in the context of GC). An object is created at Generation 0 and has its Generation incremented at a particular time. The .NET implementation uses 3 Generations, and the heap is organized into Generation 0, 1 and 2. When an object is created, it is placed in the Generation 0 section of the heap. After each garbage collection, it and all other surviving objects are promoted to the next Generation.

So when does GC happen?

Since most cleanup will involve younger objects, an efficient GC algorithm will clean younger objects more frequently. Cleaning older objects is less fruitful, so they should be cleaned comparatively rarely. The .NET GC cleans up the Generation 0 (youngest) heap most often, Generation 1 less often and Generation 2 rarely. Indicatively, Gen 0 is cleaned when it hits ~256K in size, Gen 1 around ~2MB and Gen 2 ~10MB, although these numbers are dynamic. Cleanup of older Generations always includes all younger Generations, so cleaning Generation 2 effectively means cleaning the entire heap.The actual timing of the GC is indeterminate. GC can also be triggered by code calling GC.Collect() – generally not recommended – or by the OS issuing a low memory notification.

Simple, Elegant and Creative – I love this solution

I needed to have all of the text selected when a user clicked on a text box so it would be easy to overwrite the contents without having to hit Ctrl-A. The problem was that I just couldn’t get this code working:

private void myTextbox_Enter(object sender, EventArgs e)
{
    selectedFolderPath.SelectAll();
}

I could call .SelectAll() from anywhere else and it would work fine, but just not from the .Enter event.

It turns out that:

Calling .SelectAll() during the .Enter or .GotFocus events won’t work because if the user clicked the textbox, the caret will be placed where he clicked, thus deselecting all text.

Also, calling .SelectAll() during the .Click event won’t work because the user won’t be able to select any text with the mouse; the .SelectAll() call will keep overwriting the user’s text selection. )

So, how to find a way to call .SelectAll() after the .Enter() event has been handled? My instinct (and many of the solutions I saw) all involved manually tracking the focus state with a boolean flag and either calling .SelectAll() at a later stage depending on the flag or manually redrawing the textbox as needed. All just looked like messy contortions, embarrassing compared to the code I try to write, and most likely flawed.

Then I came across this solution:

private void selectedFolderPath_Enter(object sender, EventArgs e)
{
    BeginInvoke((Action)(() => selectedFolderPath.SelectAll()));
}

It seems so blindingly obvious now.  Just call it asynchronously! 

Simple, elegant and creative.