【发布时间】:2010-10-13 02:58:04
【问题描述】:
我编写了一个多线程非托管应用程序,它在其工作线程中使用 COM 对象。一切都很顺利,直到我开始使用导出为 COM 的 .NET 对象来完成这项工作。
玩弄代码并注释掉 .NET 对象功能的一部分,我设法将其归结为在 .NET 对象中使用 COM 对象。总结一下:
- 我的程序启动了几个工作线程。
- 每个工作线程都会初始化一个基于 .NET 的 COM 对象来完成工作。
- 基于 .NET 的 COM 对象在内部使用非托管 COM 对象。
令我惊讶的是,应用程序的内存消耗开始稳步上升,直到 OutOfMemory 异常开始出现。
这是我的 .NET 实现:
void DoSomeWork()
{
IComObject O = new ComObjectClass();
try
{
// do something
}
finally
{
Marshal.ReleaseComObject(O);
}
}
如果我注释掉这个函数,内存泄漏就会消失。如果我在其中调用 GC.Collect() 内存泄漏仍然会发生。
对可能发生的事情有任何想法吗?
编辑:基于 cmets 和答案的更多信息:
- 创建的所有线程都在 MTA 中运行。
- 所有 COM 对象都实现 IMarshal 并使用 Free Threaded Marshaler。
- 做什么都没有关系 - 即使是 int i=0;i++;产生泄漏。
- ComObjetClass 指出的对象是旧的并且经过测试。这并不意味着它没有故障,但并不明显。
- 我尝试在主线程和另一个创建的线程上从 C# 程序重复创建 COM 对象。在这两种情况下,内存泄漏都消失了。似乎从非托管代码到托管代码的交叉是必不可少的。删除它的任何部分都会导致问题消失。
【问题讨论】:
-
什么是 // 做什么?有时在非托管代码中创建了您没有意识到的新对象。
-
在“do smth”中将几个 COM 对象连接在一起存在风险,这会导致内存泄漏。代码有助于了解正在发生的事情。
-
好的,如果问题真的出在 COM 对象类中怎么办?好像它有错误的引用计数机制?如果用其他 COM 对象替换它会怎样?
-
您可以通过以下方式隔离它:在原始 C++ 中创建一个示例项目,在 main() 函数中反复调用 CoCreateInstance() 和 IUnknown::Release(),观察内存消耗。如果通过这种方式可以重现泄漏,则问题出在 COM 对象中。
标签: c# multithreading com interop memory-leaks