【发布时间】:2011-09-01 00:44:07
【问题描述】:
我的问题的背景是:我正在将一个使用许多 COM 组件的消息处理应用程序从 VB6 转换为 C#。应用程序中的许多 COM 组件都是细粒度的组件,它们在消息处理循环中被大量使用且频率很高。与 VB6 应用程序相比,在 C# 应用程序中处理一组测试消息时,我看到内存使用量大幅增加(并且逐渐增长)。我在应用程序上使用了内存分析器,确认高内存使用是由于应用程序的非托管堆上的 COM 对象的活动实例造成的。我知道这些组件不会因为实时引用而“泄漏”,因为如果我将 GC.Collect() 放在消息处理循环的核心,内存使用量是平坦的,几乎与 VB6 应用程序相同(尽管性能正如人们所期望的那样严重退化)。
我已经阅读了我在 C# 中的多代垃圾收集器、运行时可调用包装器、非托管资源内存分配、Marshal.ReleaseComObject()、Marshal.FinalReleaseComObject() 等方面可以找到的所有内容。这些都没有解释为什么应用程序当相应的 RCW 符合垃圾回收条件时,它会在非托管堆中保留活动的 COM 对象。
在一些文章中,我看到了在 C# 中垃圾收集器的实际实现可能涉及优化的可能性,例如不执行特定代中所有合格对象的收集。如果这个或类似的事情是真的,它可以解释为什么没有收集和销毁合格的 RCW 及其相应的 COM 对象。另一种解释可能是,如果非托管堆中的 COM 对象的销毁不直接与相应 RCW 的集合相关联。我还没有找到任何能提供这种程度的关于如何在 .NET 中处理 COM 对象的详细信息。我需要更好地理解这一点,因为我的应用程序的内存使用目前是不可接受的。任何指针或建议将不胜感激。
编辑:我应该补充一点,我对终结器(RCW 上没有记录)和 IDisposable 接口(RCW 没有实现)非常熟悉。据我了解,Marshal.ReleaseComObject() 是显式“处理”COM 引用的正确方法。我小心地为我的应用程序中 COM 对象的每个已知用法添加了该语句,它导致内存使用没有差异。
此外,当添加显式 GC.Collect() 不会导致内存问题时,为什么缺少处理或终结代码可能会成为问题尚不清楚。 Dispose() 和终结器的存在都不会导致对象的实际集合。前者允许对象抑制其终结步骤(如果有),后者允许清理未在 RCW 中公开的非托管资源。
【问题讨论】:
标签: c# memory-management com