RCW Reference Counting Rules != COM Reference Counting Rules

Avoiding COM object leaks in managed applications that make use of COM Interop can be a daunting task. While diligent tracking of COM object references and appropriate usage of Marshal.ReleaseComObject usually works fine, COM Interop is always good for surprises.

Recently having been tracking down a COM object leak in a COM/.Net-Interop-centric application, I noticed that the CLR did not quite manage the reference count on my COM object as I expected it to do — more precisely, it incremented the referece count of a COM object when it was passed (from COM) as a method parameter to a callback implemented in .Net — which, of course, contradicts the rules of COM. So while RCWs indeed mostly follow the rules of COM reference counting, they obviously do not do follow the rules in their entirety. Once I spotted this difference, it was easy to find an explanation of this very topic by Ian Griffiths, which is worth quoting [reformatted by me]:

[…]
And by the way, the reference counting is kind of similarish to COM, in that, as you point out, things get addrefed when they are passed to you. But they’re actually not the same. Consider this C# class that
implements a COM interface:

public class Foo : ISomeComInterface
{
  public void Spong(ISomeOtherComInterface bar)
  {
    bar.Quux();
  }
}

Suppose that Spong is the only member of ISomeComInterface. (Other than the basic IUnknown members, obviously.) This Spong method is passed another COM interface as a parameter. And let’s suppose that some non-.NET client is going to call this Spong method on our .NET object via COM interop.

The reference counting rules for COM are not the same as those for the RCW in this case.

For COM, the rule here is that the interface is AddRefed for you before it gets passed in, and is Released for you after you return. In other words, you are not required to do any AddRefing or Releasing on a COM object passed to you in this way *unless* you want to keep hold of a reference to it after the call returns. In that case you would AddRef it.

Compare this with the RCW reference count. As with COM, the RCW’s reference count will be incremented for you when the parameter is passed in. But unlike in COM, it won’t be decremented for you automatically when you return.

You could sum up the difference like this:

  • COM assumes you won’t be holding onto the object reference when the method returns
  • The RCW assumes you *will* be holding onto the object reference when the method returns.

So if you don’t plan to keep hold of the object reference, then the method should really look like this:

public void Spong(ISomeOtherComInterface bar)
{
  bar.Quux();
  Marshal.ReleaseComObject(bar);
}

According to the COM rules of reference counting, this would be a programming error. But with RCWs, it’s how you tell the system you’re not holding onto the object after the method returns.

Pretty counter-intuitive… Plus, I am not aware of any official documentation on this topic.

About these ads

4 Responses to “RCW Reference Counting Rules != COM Reference Counting Rules”


  1. 2 Calvin Kwok July 20, 2011 at 2:48 am

    Thanks for your mention, Johannes. Later, I found an MSDN document that have talked about how the RCW count increase/dedrease.

    “internal marshaling count” in the following document:

    Chapter 7 — Improving Interop Performance (http://msdn.microsoft.com/en-us/library/ff647812.aspx )


  1. 1 .NET COM interoperation – Fighting with RCW memory leaks | Jisku.com - Developer Network Trackback on August 10, 2012 at 6:54 am
  2. 2 The Art of Dev Trackback on August 26, 2012 at 7:34 pm
Comments are currently closed.



Categories

Try Visual Assert, the unit testing add-in for Visual Studio (R)


NTrace: Function Boundary Tracing for Windows on IA-32

About me

Johannes Passing, M.Sc., living in Berlin, Germany.

Besides his consulting work, Johannes mainly focusses on Win32, COM, and NT kernel mode development, along with Java and .Net. He also is the author of cfix, a C/C++ unit testing framework for Win32 and NT kernel mode, Visual Assert, a Visual Studio Unit Testing-AddIn, and NTrace, a dynamic function boundary tracing toolkit for Windows NT/x86 kernel/user mode code.

Contact Johannes: jpassing (at) acm org

Johannes' GPG fingerprint is BBB1 1769 B82D CD07 D90A 57E8 9FE1 D441 F7A0 1BB1.

LinkedIn LinkedIn Profile
Xing Xing Profile
Twitter Follow me on Twitter (new)

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: