1
votes

I am working on an Outlook Addin where I create a lot of COM objects(Outlook mail, Outlook folder etc). My understanding is that since these objects are COM objects,CLR won't release memory from these objects and i'll have to take care of releasing memory from these objects.So to release memory from these object I use

Marshal.ReleaseComObject(Object);

But unfortunately this doesn't seem to work.Then I put a GC.Collect() statement after Marshal.ReleaseComObject(Object);and this worked.I didn't get any memory related exception after that. My question is that if CLR can relase memory from COM objects, why it doesn't do it by itself. and if it can't then how GC.Collect() statement worked in my case.

2

2 Answers

7
votes

You need to have a good understanding of the Runtime Callable Wrapper in order to use COM with .Net. Basically, everything you have in your .Net code that is a reference to a COM object, is really a reference to an RCW. The RCW manages the reference count on the underlying COM object by counting how many references are to it, and when the reference count on it drops to 0, it will call Release (once) on the underlying object. While the RCW is live, it will maintain a single reference on the COM object.

The ReleaseComObject API will decrease the reference count on the RCW by 1. If this brings the reference count on the RCW to 0, then the RCW will call Release on the COM object, otherwise not. There is also FinalReleaseComObject which will cause the reference count on the RCW to go to 0 (thus cause the RCW to call Release) although this is kind of risky if you have other references outstanding on the RCW as they will probably error.

"Normally", the references on the RCW are managed when the objects which have a reference to it are garbage collected - this would explain why you saw the COM object be released when you forced the garbage collection. This, combined with what we know about how the RCW works tells us that there were other references on the RCW that you also would have "needed" to call ReleaseComObject on in order to cause it to Release.

Calling ReleaseComObject is kind of an end run around the .Net runtime, and you have to be super careful to manage all of the references that are created. Some of the references that are created are "implicit" references - these come about because of doing things like calling into properties which return references which you then call in on. This is sometimes refered to as the "too many dots" problem, when you do something like this:

object.foo.blah.baz.something()

The "foo", "blah" and "baz" are probably all references to some COM object somewhere that you need to think about.

0
votes

Did you try to allocate memory after Marshal.ReleaseComObject? Because, you know, the garbage collector will run at its own will, which means typically when memory is being allocated, and not just when you think it should run (unless you call GC.Collect, of course).

I didn't have any problems with automatically releasing COM objects so far, and I called Marshal.ReleaseComObject only when I want the COM server to be immediately shut-down.