7

I have been developing office solutions in VBA for a while now and have fairly complete knowledge regarding office development in VBA. I have decided it is time to learn some real programming with .Net and am having some teething problems.

Having looked through a bunch of articles and forums (here and elsewhere), there seems to be some mixed information regarding memory management in .Net when using COM objects.

Some people say I should always deterministically release COM objects and others say I should almost never do it.

People saying I should do it:

The book 'Professional Excel Development' on page 861.

This stack exchange question has been answered by saying "every reference you make to a COM object must be released. If you don't, the process will stay in memory"

This blog suggests using it solved his problems.

People saying I should not do it:

This MSDN blog by Eric Carter states "In VSTO scenarios, you typically don't ever have to use ReleaseCOMObject."

The book 'VSTO for Office 2007' which is co-authored by Eric Carter seems to make no mention whatsoever of memory management or ReleaseComObject.

This MSDN blog by Paul Harrington says don't do it.

Someone with mixed advice:

Jake Ginnivan says I should always do it on COM objects that do not leave the method scope. If a COM object leaves the method scope then forget about it. Why can't I just forget about it all the time then?

The blog by Paul Harrington seems to suggest that the advice from MS has changed sometime in the past. Is it the case that calling ReleaseCOMObject used to be best practice but is not anymore? Can I leave the finer details of memory management to MS and assume that everything will be mostly fine?

Community
  • 1
  • 1
Chechy Levas
  • 2,206
  • 1
  • 13
  • 28

2 Answers2

2

I try to adhere to the following rule in my interop development regarding ReleaseComObject.

If my managed object implements some kind of shutdown protocol similar to IDisposable, I call ReleaseComObject on any child COM objects I hold references to. Some examples of the shutdown protocols I'm talking about:

  • IObjectWithSite.SetSite(null)
  • IOleObject.SetClientSite(null)
  • IOleObject.Close()
  • IDTExtensibility2.OnDisconnection
  • IDTExtensibility2.OnBeginShutdown

  • IDisposable.Dispose itself

This helps breaking potential circular references between .NET and native COM objects, so the managed garbage collector can do its job unobstructively.

Perhaps, there's something similar which can be used in your VSTO interop scenario (AFAIR, IDTExtensibility2 is relevant there).

If the interop scenario involves IPC COM calls (e.g., when you pass a managed event sink object to an out-of-proc COM server like Excel), there's another option to track external references to the managed object: IExternalConnection interface. IExternalConnection::AddConnection/ReleaseConnection are very similar to IUnknown::AddRef/Release, but they get called when a reference is added from another COM appartment (including apartments residing in separate processes).

IExternalConnection provides a way to implement an almost universal shutdown mechanism for out-of-proc scenarios. When the external reference count reaches zero, you should call ReleaseComObject on any external Excel objects you may be holding references to, effectively breaking any potential circular COM references between your process and Excel process. Perhaps, something like this has already been implemented by VSTO runtime (I don't have much experience with VSTO).

That said, if there is no clear shutdown mechanism, I don't call ReleaseComObject. Also, I never use FinalReleaseComObject.

noseratio
  • 59,932
  • 34
  • 208
  • 486
  • 1
    An expert on async code and COM interop? Do you enjoy finding the hardest topics in C# to be come the expert in? ;) – Scott Chamberlain Jun 21 '14 at 04:45
  • @ScottChamberlain, far from being an expert, rather certain applied knowledge here and there, but thanks for your good words :) – noseratio Jun 21 '14 at 06:45
  • Thanks for you help. I guess the bottom line is 'it depends'. I think the only way to deal with this is to learn about memory management in COM vs .Net. I was looking for an easy way out but I guess there is none. – Chechy Levas Jun 21 '14 at 08:46
  • 1
    @Travis, yes, it depends, but it doesn't mean you can simply ignore `ReleaseComObject`. Just keep in mind, there's no garbage collector in COM, so any two `IUnknown` objects referencing each other may never get released, unless there's an established interface to shutdown at least one of them, explicitly. E.g., it may lead to a zombie instance of Excel.exe hanging there until reboot, unless you do `application.Visible = false; application.Quit()`. – noseratio Jun 22 '14 at 01:20
0

You should not ignore it, if you are working with the Office GUI! Like your second link states:

Every reference you make to a COM object must be released. If you don't, the process will stay in memory.

This means, that your objects will remain in memory if you do not explicitly release them. Since they are COM objects, the garbage collector is responsible for releasing them. However, Excel and the other fancy tools are implemented with no knowledge of the garbage collector in .NET. They relate on deterministic release of memory. If you are requesting an object from excel and do not properly release it, it might be that your application does not close correctly, because it wait's until your resources are released. If your objects live long enought to get into gen1 or gen2, then this can take hours or even days!

All considerations about not releasing COM objects are targeting multithreaded scenarios or scenarios where you are forced to push around many com objects over multiple instances. As a good advice, allways create your com objects as late as possible and release them as soon as possible in the opposite order than created. Also you should think about keeping your interop instances private wherever possible. This reduces the possibility that other threads or instances are accessing the object while you have already released it.

Carsten
  • 11,287
  • 7
  • 39
  • 62
  • 1
    Thanks. Regarding the multithreaded scenarios, if not releasing COM objects is OK then there must be some way to recover the memory. I don't understand why this doesn't apply to single threaded scenarios. Also, the guy who literally wrote the book on VSTO (Eric Carter as linked above) states "In VSTO scenarios, you typically don't ever have to use ReleaseCOMObject". I think ultimately I am unable to understand the nuances of this issue until I learn a lot more about memory management in general. – Chechy Levas Jun 24 '14 at 14:31
  • Office consists out of native applications, where you have to take care of allocating and releasing memory on your own. COM provides the interface `IUnknown` that supports automatic memory management, based on reference counters. This is different to .NET, where the garbage collector searches for "releaseable" objects. Both systems are not directly compatible and that's why you should take care of the memory management on your own. Adam Nathan also describes Office interop scenarios this way in his book ".NET and COM - The complete interopability guide". ;) – Carsten Jun 25 '14 at 07:56