I’m such a statistics junkie that I found another interesting Google query that return my site and someone clicked on the link and got in (thanks again ShinyStat guys for that cool feature).

Anyhow, the query that got my attention today was “marshal.releasecomobject spinning“.

Now this is interesting and I thought I would elaborate a bit on Marshal.ReleaseComObject and what problems that can happen due to calling it (or not calling it).

First, we need to understand what Marshal.ReleaseComObject actually does and then we will cover the two assumptions mentioned above.

What does Marshal.ReleaseComObject actually do?
.NET can access COM objects through something called a Runtime Callable Wrapper (RCW).

The RCW is the wrapper for a COM object. There is one per a COM object instance and what it does is to provide the interface between .NET and COM.
COM uses reference counting to know when to release and destroy an object. .NET, on the other hand, is a garbage collected environment and these two approaches are opposite to each other.

COM will release an object the minute the minute the object’s ref count reached zero.
.NET will only release the COM object when no one is referencing the RCW and it is ready to be finalized.

RCW encapsulates the COM object and ALWAYS keeps a ref count of 1 to that object. An exception to this would be when the RCW is marshaled to another AppDomain, in which case it will increase the ref count of the COM object.

The RCW is a managed object and therefore have all the properties of a managed object. It will not be considered garbage as long as it is reachable from another object (and that object is either rooted or is referenced by a rooted object… You get the idea).

RCW has a finalizer in which the RCW will de-reference the COM object, get it destroyed and its memory freed (assuming it is not marshaled to another AppDomain). This means that it takes at least two garbage collections until a COM object that is being referenced from .NET will actually get released after no one references it.

So I did call Marshal.ReleaseComObject, so what?
If you did call Marshal.ReleaseComObject when you no longer need a certain COM object its great. It means that you release the memory of that object right away and you are not holding it until the next GC.

It can, however, cause a few problems:

  • If, for some reason the COM object is an STA object, call Marshal.ReleaseComObject means you will have to context switch to the STA thread that created that object (unless you are in the STA thread that created the object). This means that if you are not careful enough there is a possibility for a deadlock (for more information about deadlocks, refer to my previous posts about deadlocks).
  • You are passing the reference to that RCW around and you call Marshal.ReleaseComObject on it but you still have a reference to the RCW itself (which is still alive because its a manged object and will only die when it has no references to it and get Garbage Collected) in another place.
    In this case (which is an easy one), the RCW will throw an exception which states that you actaully disconnected the underlying COM object so you have a valid RCW object but it points to a dead COM object and you have nothing to do with it now.

I didn’t call Marshal.ReleaseComObject, so sue me

If you didn’t call Marshal.ReleaseComObject you might get into a different set of problems:

  • If you have STA objects you might get to a blocked finalizer thread situation.
  • It will just take more time for this memory to get released because, as I’ve said, the RCW has a finalizer and it takes at least 2 garbage collections to actually clean it and the memory its underlying COM object takes.

As you can see by this short post, Marshal.ReleaseComObject is an important thing that should not be taken lightly when used. You need to know when to use it and be aware of the consequences.

Happy COM interoping and memory releasing 😉

  • Carl Taylor

    Coming from a C++ background, I much prefer managing the lifetime of COM objects directly rather than relying on the garbage collector.

    What is the impact of calling Marshal.ReleaseComObject(pISomeIntfc) and then immediately setting pISomeIntfc to null?

    In my case I have a C# class that creates and holds a reference to a RCW. I added a public Release() method that calls Marshal.ReleaseComObject(pISomeIntfc) and then immediately sets pISomeIntfc to null.

    When the garbage collector finally gets around to destroying my class instance, I am hoping the COM instance is already properly cleaned up due to a prior call to Release(). Any problems here?

  • Carl, calling Marshal.ReleaseComObject basically dereferences the underlying COM object which, as far as COM object goes, if the ref count is 0 the COM object will be release from memory.

    Setting the RCW to null after calling Marshal.ReleaseComObject is good practice (so no one references an RCW that basically points to nothing). What it will do when it reaches the GC is simply to release the memory associated with the RCW object itself (not the COM object behind it).

    I don’t see any problems with this approach as long as everyone understands NOT to use the RCW or any other method/object that tries to reference it after your Release() function has been called.

  • Sam

    I hadn’t heard of Marshal.ReleaseComObject before. Thanks for the update.

  • Pingback: The Art of Dev()