在哪里可以找到有关 .NET 中 COM 资源处理的更多详细信息?

发布于 2024-11-09 07:09:27 字数 1065 浏览 0 评论 0原文

我的问题的背景是这样的:我正在将一个使用许多 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 中公开的非托管资源。

The background for my question is this: I am converting a message processing app that uses many COM components from VB6 to C#. Many of the COM components in the application are fine-grained components that are used in high numbers and frequency within message processing loops. I am seeing a massive (and progressively growing) increase in memory usage when processing a set of test messages in the C# app as compared to the VB6 app. I used a memory profiler on the application that confirmed that the high memory usage was due to live instances of COM objects on the application's unmanaged heap. I know that these components are not being "leaked" due to live references because if I put a GC.Collect() at the core of the message processing loop, the memory usage is flat and nearly identical to the VB6 app (although the performance degrades horribly as one would expect).

I have read everything I can find on the multi-generation garbage collector in C#, runtime callable wrappers, unmanaged resource memory allocation, Marshal.ReleaseComObject(), Marshal.FinalReleaseComObject(), etc. None of it explains why the application is holding onto live COM objects in the unmanaged heap when the corresponding RCWs are eligible for garbage collection.

In some articles, I have seen allusions to the possibility that the actual implementation of the garbage collector in C# may involve optimizations such as not performing collection of all eligible objects in a particular generation. If this or something like it were true, it could explain why eligible RCWs and their corresponding COM objects are not collected and destroyed. Another explanation could be if the destruction of a COM object in the unmanaged heap is not directly tied to the collection of its corresponding RCW. I have not found anything that offers this degree of detail on how COM objects are handled in .NET. I need to understand this better because my app's memory usage is currently unacceptable. Any pointers or recommendations would be greatly appreciated.

Edit: I should add that I am quite familiar with finalizers (which are not documented to exist on RCWs) and the IDisposable interface (which RCWs do not implement). To the best of my understanding, Marshal.ReleaseComObject() is the proper method of explicitly "disposing" of a COM reference. I was careful to add that statement for every known usage of a COM object in my app and it resulted in no difference in memory usage.

Further, it is not clear why a lack of disposal or finalization code could be the problem when the addition of an explicit GC.Collect() results in no memory problems. Neither Dispose() nor the presence of a finalizer result in the actual collection of objects. The former permits an object to suppress its finalization step (if any) and the latter allows for the cleanup of unmanaged resources of which none are exposed in an RCW.

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

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

发布评论

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

评论(2

撑一把青伞 2024-11-16 07:09:27

您是否在实例化 COM 对象的类中正确实现了 IDisposable?

您需要实现 IDisposable 并在 Dispose() 方法中处置您的 COM RCW。然后,实例化实现 IDisposable 的类的所有代码都应显式调用它或使用 using() 语句来调用它,如下所示:

var first = new DisposableObject();
...
first.Dispose();

IDisposable

using(var first = new DisposableObject())
{
   ...
}

是让 CLR 及时处理这些对象并确保您丢失 COM 引用。

Are you implementing IDisposable properly in the classes that instantiate your COM objects?

You need to implement IDisposable and dispose of your COM RCW's in the Dispose() method. Then all code that instantiates classes that implement IDisposable should call it either explicitly or by using a using() statement, like so:

var first = new DisposableObject();
...
first.Dispose();

and

using(var first = new DisposableObject())
{
   ...
}

IDisposable is the only way to get the CLR to dispose of these objects in a timely manner and to make sure you lose COM references.

雾里花 2024-11-16 07:09:27

使用终结器或析构函数进行清理COM 对象使用的内存。

http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

或者,如果您希望立即清理对象,您可以实现 IDispose,以及在实例化 COM 对象的代码中使用 using 语句。

Use a Finalizer or destructor to clean up the memory used by the COM objects.

http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

Alternatively, if you want the objects to clean up immediately, you can implement IDispose, and use a using statement in your code that instantiates the COM object.

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