SharpDX Resources

As a long term .net programmer I am used to a managed memory runtime environment and know all about the Dispose pattern used to release managed resources. However for some time I’ve been concerned with the memory leaks I was seeing in my SharpDX based 3D landscape.

This post is a reminder to all SharpDX .net programmers that Dispose() implemented in SharpDX objects does not work like the standard Dispose pattern for .net.

All SharpDX objects are wrapped COM objects and are subject to proper disposal via reference counting. The .net runtime caters for all reference counts for .net classes and collects their resources as soon as there are no references to them in the managed call stack (and thread local storage). COM places the requirement to manage the lifetime of objects firmly on the programmer, who must add and remove reference counts to objects as new references to them are stored.

Using the standard .net Dispose pattern allows me to handle the COM de-reference without any problems; the SharpDX documentation tells us that “Dispose” is used to dereference the counter.

What I forgot is that COM references aren’t just created when you instantiate a new instance, but also if you receive an instance reference from the SharpDX factory. So the general pattern;

SharpDX.DirectX11.Texture2D tex = new SharpDX.DirectX11.Texture2D();
.. do some work
tex.Dispose();

works perfectly Ok. What isn’t so obvious is that;

SharpDX.Direct3D11.DepthStencilView dsv;
SharpDX.Direct3D11.RenderTargetView[] rtvs = 
   this.Context.OutputMerger.GetRenderTargets(8, out dsv);

to query a list of the existing render targets, also increments the reference count of those RenderTargetView instances, and the DepthStencilView. So you need to remember to dispose of those too.

As a .net programmer this is odd, but manageable. What is particulary weird feeling is that Dispose() is designed in .net to be used when the programmer knows they have the last instance reference to a managed class. If you have four references to a single instance, you clearly should not call Dispose() until you know that you are holding the very last instance, otherwise any other reference pointers will suddenly find themselves holding disposed classes.

When using Dispose with the SharpDX classes you call it as soon as you know your particular reference is going to go out of scope – irrespective of how many other references to the same instance exists. Dispose() doesn’t acutally release any resources – it simply decrements the COM reference count. The SharpDX class factory does the resource release and COM deallocation.

Becuase it is not obvious when looking at code whether you are using a .net managed class or a wrapped SharpDX COM class, and because Dispose() means something entirely differnet in each case I decided to create extension methods for all the SharpDX classes;

/// <summary>
/// Hides the confusion between Dispose (a .net concept) and handle counting (a com concept).
/// </summary>
/// <param name="leasedObject"></param>
public static void ReleaseReference(this SharpDX.Direct3D11.DeviceContext leasedObject)
{
    leasedObject.Dispose();
}

This means my code looks like this;

SharpDX.DirectX11.Texture2D tex = new SharpDX.DirectX11.Texture2D();
.. do some work
tex.ReleaseReference();

Which is a lot more self descriptive. I like making code more maintainable this makes me stop and think when I look at it, and I instantly know whats going on. I wish the SharpDX bods had not used the existing Dispose() method to do their reference counting – but I can see why they did.

Advertisements