处理COM对象内存泄漏

时间:2014-10-23 15:48:14

标签: c# memory-leaks com

我有一个读取和写入数据的COM对象。我需要尽快使用COM对象进行读写。

while(!stopLoop)
{
  DateTime t1;

  foreach(Item in Data)
  {
    ReadData(...);
    //...
  }

  DateTime t2;
  TimeSpan loopTime = t2 - t1;
}

我写了一些代码然后运行它。起初我的loopTime为200毫秒,但速度越来越慢,45分钟后花了大约3秒钟。内存使用量在同一时间内翻了一倍。

我查看了VMMap并且:随着时间的推移,只有非托管堆内存增加了。所以我猜我在COM对象中有内存泄漏。

好的,谷歌搜索并试着跟随:

System.Runtime.InteropServices.Marshal.ReleaseComObject(myObject);

创建新对象并初始化后,我可以再次阅读:

antiLeakCounter = 0; //as proposed in the comments by Hans Passant

public object ReadData(...)
{
  object obj = new object();
  myComObj.Read(..., ref obj);

  if(++antiLeakCounter == 100)
  {
    //TryRemoveLeak();
    antiLeakCounter = 0;
  }

  return obj;
}

private void TryRemoveLeak()
{
  ReleaseComObject(myComObj);
  myComObj = new MyComClass();
  InitMyComObj();
}

使用ReleaseObject,我会再次获得持续时间。我不确定COM对象现在是否有效。 myComObj.Read(..., ref obj);通常会返回我可以使用is bool / byte[] / int检查的ref对象,但在ReleaseComObject之后重新生成ref对象只会返回{{1}所以我现在不能施展它。所以...我的娱乐活动一定有问题。

如何正确重新创建COM对象?或者有不同的方法来防止这些泄漏?


编辑:

我使用GC.Collect,AddMemoryPressure等进行了测试,但无法使循环时间稳定:

object

测试1:

private void TryRemoveLeak()
{
  //instead of ReleaseComObject...
}

Test 2

GC.Collect();

Test 3

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();

测试4:

GC.Collect(GC.GetGeneration(myComObj), GCCollectionMode.Optimized);

COM对象与另一个名为PLCSIM的应用程序交互。

public object ReadData(...)
{
  object obj = new object();
  GC.AddMemoryPressure(byteSizeOfObj);
  myComObj.Read(..., ref obj);

  GC.RemoveMemoryPressure(byteSizeOfObj); //after returning, the obj is dead, right?
  return obj;
}

我检查了PLCSIM,也可以看到内存泄漏。它在同一时间内像我的申请一样泄漏了几乎相同的数量。

1 个答案:

答案 0 :(得分:0)

我的问题是COM对象的错误用法。

而不是:

object obj = new object();
myComObj.Read(..., ref obj);

我必须使用正确的类型:

object obj;

switch(...)
{
  case(...): obj = new int(); break;
  case(...): obj = new short(); break;
  case(...): obj = new byte(); break;
  ...
}
myComObj.Read(..., ref obj);

所以在这种情况下,我不需要重新创建我的COM对象,也不需要创建ReleaseComObjectGC.Collect()