3

I have an application that was originally written in VB6 that I used a tool to convert to C# with pretty good success from a functional perspective. It processes a high volume of message using lots of small to medium sized COM (C++) objects.

I noticed that a particular test run in the old VB6 app that ran using less than 40M of memory required nearly 900M in the C# app. If I put a GC.Collect() in the inner-most message processing loop of the C# app, it uses the same or less memory as the VB6 app although it is then really, really slow. This leads me to believe there is no "leak" in the absolute sense of the word.

I then ran the C# app through the AQTime memory profiler and it reported that there were an excessive number of COM/C++ objects live on the heap. I hypothesized that this was because the runtime callable wrappers around the COM objects were quite small and never (or rarely) triggered collection in C# even if their referenced COM objects were substantially larger. I thought I could address this by adding explicit Marshal.ReleaseComObject() calls around the COM objects in the C# app. I went and did this in a lot of places where the lifetime of the COM objects was easy to determine. I noticed only a very slight reduction in memory usage.

I am wondering why I did not have better success with this. Looking through the static methods in the Marshal class, I see some that lead me to believe either tha I may be missing some subtlety in the handling of COM references or that my assumption that they are immediately destroyed when the RCW's reference count reaches zero is incorrect.

I would appreciate any suggestions for other approachs that I could try or other things that I may have overlooked or misunderstood.

6
  • What happens if you don't do GC.Collect? Does it crash? Commented Mar 15, 2011 at 2:12
  • If I remove the GC.Collect() call, memory usage goes about to about 900M. It has never crashed, but that kind of memory usage isn't acceptable when the old VB6 app used less than 40M while using the same COM objects. Commented Mar 15, 2011 at 2:45
  • @Dan: it's virtual memory, not physical. Excessive paging would be a better measure than total memory "used". Commented Mar 15, 2011 at 2:47
  • Hmm, I was basing the memory usage off what was reported by Task Manager which may not be the most accurate, but according to AQTime, the managed heap size was well under 100M so the size of the COM objects was about 10x greater. Shouldn't they be immediately released once their RCW's ref count reaches zero? Commented Mar 15, 2011 at 3:00
  • 1
    Right, Task Manager is hopelessly inaccurate for this type of thing. Use a different memory profiler. Commented Mar 15, 2011 at 6:47

1 Answer 1

3

Sorry for the link instead of a good synopsis, but I've never had that issue myself as I've dealt with IE and mshtml in a long lived scenario.

The article states:

When using a COM object from a .NET-based application, there are two objects involved: the RCW and the COM object (or objects). Garbage collection is only aware of the size of the RCW (which can be small), not of the COM object (which may be large). Therefore, while the .NET-based application might release the RCW, garbage collection may not reclaim the RCW even as memory runs out. As long as the RCW stays in memory, the COM object that it manages stays in memory also.

There are two mechanisms that ensure that COM objects are released from memory: the AppDomain object and the ReleaseComObject method. Using an AppDomain provides the simplest solution to managing COM objects but has performance costs and can expose a security risk. Using ReleaseComObject avoids those costs but requires more careful planning and coding.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, I was unaware of the AppDomain option, but that may not be ideal for my situation since performance is important in the inner message processing loop.
@Dan - I thought your loop was creating and releasing quite a few COM objects. If so, that in of itself is not a very performant thing to do. I'd surmise that ReleaseComObject is a really good option worth implementing and profiling.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.