我有一个最初用VB6编写的应用程序,我使用了一个工具转换为C#,从功能角度来看非常成功。它使用大量中小型COM(C ++)对象处理大量消息。
我注意到在使用少于40M内存的旧VB6应用程序中运行的特定测试需要在C#应用程序中接近900M。如果我将GC.Collect()放在C#应用程序的最内层消息处理循环中,它使用与VB6应用程序相同或更少的内存,尽管它真的非常非常慢。这使我相信绝对意义上没有“泄漏”。
然后我通过AQTime内存分析器运行C#应用程序,它报告堆上有过多的COM / C ++对象。我假设这是因为COM对象周围的运行时可调用包装器非常小,并且从未(或很少)触发C#中的集合,即使它们引用的COM对象要大得多。我以为我可以通过在C#app中的COM对象周围添加显式的Marshal.ReleaseComObject()来解决这个问题。我去了很多很容易确定COM对象生命周期的地方。我注意到内存使用量只有轻微的减少。
我想知道为什么我没有取得更好的成功。通过查看Marshal类中的静态方法,我看到一些让我相信我可能在处理COM引用时遗漏了一些微妙之处,或者我认为当RCW的引用计数达到零时它们立即被销毁是不正确的
对于我可以尝试的其他方法或我可能忽略或误解的其他方法,我将不胜感激。
答案 0 :(得分:3)
很抱歉链接而不是一个好的大纲,但我自己从来没有遇到过这个问题,因为我在很长一段时间内处理过IE和mshtml。
文章指出:
从基于.NET的应用程序使用COM对象时,涉及两个对象:RCW和COM对象(或对象)。垃圾收集只知道RCW的大小(可能很小),而不是COM对象的大小(可能很大)。因此,虽然基于.NET的应用程序可能会释放RCW,但即使内存耗尽,垃圾回收也可能无法回收RCW。只要RCW保留在内存中,它管理的COM对象也会保留在内存中。
有两种机制可确保从内存中释放COM对象:AppDomain对象和ReleaseComObject方法。使用AppDomain提供了管理COM对象的最简单的解决方案,但是具有性能成本并且可能存在安全风险。使用ReleaseComObject可以避免这些成本,但需要更仔细的规划和编码。