使用大量COM对象的C#中内存使用过多

使用大量COM对象的C#中内存使用过多,c#,memory-leaks,memory-management,com-interop,C#,Memory Leaks,Memory Management,Com Interop,我有一个最初用VB6编写的应用程序,我使用一个工具将其转换为C#,从功能的角度来看,它非常成功。它使用大量中小型COM(C++)对象处理大量消息 我注意到,在旧的VB6应用程序中运行一个使用不到40M内存的特定测试,在C#应用程序中需要近900M内存。如果我将GC.Collect()放在C#应用程序最内部的消息处理循环中,它使用的内存与VB6应用程序相同或更少,尽管它的速度非常非常慢。这让我相信绝对意义上的“漏洞”是不存在的 然后我通过AQTime内存分析器运行C#应用程序,它报告堆上存在过多的

我有一个最初用VB6编写的应用程序,我使用一个工具将其转换为C#,从功能的角度来看,它非常成功。它使用大量中小型COM(C++)对象处理大量消息

我注意到,在旧的VB6应用程序中运行一个使用不到40M内存的特定测试,在C#应用程序中需要近900M内存。如果我将GC.Collect()放在C#应用程序最内部的消息处理循环中,它使用的内存与VB6应用程序相同或更少,尽管它的速度非常非常慢。这让我相信绝对意义上的“漏洞”是不存在的

然后我通过AQTime内存分析器运行C#应用程序,它报告堆上存在过多的COM/C++对象。我假设这是因为COM对象周围的运行时可调用包装器非常小,并且从未(或很少)触发C#中的集合,即使它们引用的COM对象大得多。我想我可以通过在C#app中围绕COM对象添加显式Marshal.ReleaseComObject()调用来解决这个问题。我在很多很容易确定COM对象生命周期的地方做了这项工作。我只注意到内存使用量略有减少

我想知道为什么我在这方面没有取得更好的成功。通过查看Marshal类中的静态方法,我看到了一些使我相信我可能在处理COM引用时遗漏了一些微妙之处,或者我认为当RCW的引用计数达到零时它们会立即被销毁的假设是不正确的


如果您对我可以尝试的其他方法或我可能忽略或误解的其他方法有任何建议,我将不胜感激。

很抱歉,我没有一个好的概要,但我自己从来没有遇到过这个问题,因为我在一个长期存在的场景中处理过IE和mshtml

该条规定:

从基于.NET的应用程序中使用COM对象时,涉及两个对象:RCW和COM对象(或多个对象)。垃圾收集只知道RCW的大小(可以很小),而不知道COM对象的大小(可能很大)。因此,尽管基于.NET的应用程序可能会释放RCW,但即使内存耗尽,垃圾回收也可能不会回收RCW。只要RCW留在内存中,它管理的COM对象也会留在内存中

有两种机制可以确保COM对象从内存中释放:AppDomain对象和ReleaseComObject方法。使用AppDomain提供了管理COM对象的最简单解决方案,但会带来性能成本,并可能暴露安全风险。使用ReleaseComObject可以避免这些成本,但需要更仔细的规划和编码


如果不执行GC.Collect,会发生什么?它崩溃了吗?如果我删除GC.Collect()调用,内存使用量将达到900M左右。它从未崩溃过,但当旧的VB6应用程序在使用相同的COM对象时使用的内存不足40M时,这种内存使用是不可接受的。@Dan:它是虚拟内存,不是物理内存。过度分页比总内存“已使用”更好。嗯,我是根据任务管理器报告的内存使用情况来计算内存使用情况的,这可能不是最准确的,但根据AQTime,托管堆的大小远小于100M,因此COM对象的大小大约是它的10倍。当他们的RCW的ref计数达到零时,他们不应该立即被释放吗?对,任务管理器对于这种类型的事情是非常不准确的。使用不同的内存探查器。谢谢,我不知道AppDomain选项,但这可能不适合我的情况,因为性能在内部消息处理循环中很重要。@Dan-我以为你的循环正在创建和释放相当多的COM对象。如果是这样的话,这本身就不是一件非常有效的事情。我猜想ReleaseComObject是一个非常值得实现和分析的好选择。