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

发布于 2024-10-22 02:58:29 字数 663 浏览 1 评论 0 原文

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

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

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

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

亣腦蒛氧 2024-10-29 02:58:29

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

文章指出:

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文