我有一个读取和写入数据的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...
}
GC.Collect();
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,也可以看到内存泄漏。它在同一时间内像我的申请一样泄漏了几乎相同的数量。
答案 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对象,也不需要创建ReleaseComObject
或GC.Collect()
。