【问题标题】:Memory leaks in a multi-threaded application using COM & C#使用 COM 和 C# 的多线程应用程序中的内存泄漏
【发布时间】:2010-10-13 02:58:04
【问题描述】:

我编写了一个多线程非托管应用程序,它在其工作线程中使用 COM 对象。一切都很顺利,直到我开始使用导出为 COM 的 .NET 对象来完成这项工作。

玩弄代码并注释掉 .NET 对象功能的一部分,我设法将其归结为在 .NET 对象中使用 COM 对象。总结一下:

  1. 我的程序启动了几个工作线程。
  2. 每个工作线程都会初始化一个基于 .NET 的 COM 对象来完成工作。
  3. 基于 .NET 的 COM 对象在内部使用非托管 COM 对象。

令我惊讶的是,应用程序的内存消耗开始稳步上升,直到 OutOfMemory 异常开始出现。

这是我的 .NET 实现:

void DoSomeWork()
{
    IComObject O = new ComObjectClass();
    try
    {
        // do something
    }
    finally
    {
        Marshal.ReleaseComObject(O);
    }

}

如果我注释掉这个函数,内存泄漏就会消失。如果我在其中调用 GC.Collect() 内存泄漏仍然会发生。

对可能发生的事情有任何想法吗?

编辑:基于 cmets 和答案的更多信息:

  1. 创建的所有线程都在 MTA 中运行。
  2. 所有 COM 对象都实现 IMarshal 并使用 Free Threaded Marshaler。
  3. 做什么都没有关系 - 即使是 int i=0;i++;产生泄漏。
  4. ComObjetClass 指出的对象是旧的并且经过测试。这并不意味着它没有故障,但并不明显。
  5. 我尝试在主线程和另一个创建的线程上从 C# 程序重复创建 COM 对象。在这两种情况下,内存泄漏都消失了。似乎从非托管代码到托管代码的交叉是必不可少的。删除它的任何部分都会导致问题消失。

【问题讨论】:

  • 什么是 // 做什么?有时在非托管代码中创建了您没有意识到的新对象。
  • 在“do smth”中将几个 COM 对象连接在一起存在风险,这会导致内存泄漏。代码有助于了解正在发生的事情。
  • 好的,如果问题真的出在 COM 对象类中怎么办?好像它有错误的引用计数机制?如果用其他 COM 对象替换它会怎样?
  • 您可以通过以下方式隔离它:在原始 C++ 中创建一个示例项目,在 main() 函数中反复调用 CoCreateInstance() 和 IUnknown::Release(),观察内存消耗。如果通过这种方式可以重现泄漏,则问题出在 COM 对象中。

标签: c# multithreading com interop memory-leaks


【解决方案1】:

可能是您的 COM 包装器对象需要切换到 STA 线程才能完成。如果您的 STA 不发送消息,这将永远不会发生,因此永远不会调用 finalize,这反过来会导致内存泄漏。

this KB 中有更多信息。

【讨论】:

    【解决方案2】:

    您好,建议您使用以下代码。

         if (feature != null) 
            { 
                while (Marshal.ReleaseComObject(feature) > 0) 
                { }
                feature=null;
            }
    

    如果您使用 com 对象作为引用类型。前任。光标。 如果你只是在做 Marshal.ReleaseComObject(O);

    它只会释放一个引用,而其余的引用将保留在内存中,这样更好地释放所有引用。

    【讨论】:

      猜你喜欢
      • 2012-06-14
      • 1970-01-01
      • 2015-08-14
      • 1970-01-01
      • 2012-06-24
      • 2013-04-28
      • 1970-01-01
      • 1970-01-01
      • 2012-09-16
      相关资源
      最近更新 更多