C# 使用GC.AddMemoryPressure触发更频繁的运行时可调用包装器(RCW)终结是否合适?

C# 使用GC.AddMemoryPressure触发更频繁的运行时可调用包装器(RCW)终结是否合适?,c#,com,garbage-collection,C#,Com,Garbage Collection,我的.NET应用程序在很短的时间内使用了大量的RCW(在不到一秒钟的时间内使用了数千个RCW)。我可以通过以下性能计数器来衡量这种行为: -进程->句柄计数 -.NET CLR内存->#正在使用的接收器块 我们已经在RCWs周围正确地实现了IDisposable包装器对象;我们在各种RCW上以适当的顺序调用Marshal.finalEleaseComObject 根据,在RCW最终确定之前,RCW下的COM对象实际上不会被清理 使用GC.AddMemoryPressure强制GC更快地清理RCW

我的.NET应用程序在很短的时间内使用了大量的RCW(在不到一秒钟的时间内使用了数千个RCW)。我可以通过以下性能计数器来衡量这种行为: -进程->句柄计数 -.NET CLR内存->#正在使用的接收器块

我们已经在RCWs周围正确地实现了IDisposable包装器对象;我们在各种RCW上以适当的顺序调用Marshal.finalEleaseComObject

根据,在RCW最终确定之前,RCW下的COM对象实际上不会被清理


使用GC.AddMemoryPressure强制GC更快地清理RCW以防止内存不足错误是否合适?

您应该维护对每个COM对象的显式托管引用,并在不再需要COM对象时立即调用

此方法用于显式控制托管代码中使用的COM对象的生存期。您应该使用此方法及时释放包含资源引用的基础COM对象,或者在必须按特定顺序释放对象时释放该对象

请注意,使用“双点”会导致运行时创建隐藏的托管引用,例如Excel中的常见模式:

Worksheet sheet = excelApp.Worksheets.Open(sheetName);
创建包装工作表的隐藏托管对象。首选的方法是

Worksheets sheets = excelApp.Worksheets; 
Worksheet sheet = sheets.Open(sheetName);
您可以对这些托管变量中的每一个调用Marshal.ReleaseComObject,调用顺序与创建顺序相反

如果您确实有对COM对象的隐藏引用,那么我看到的唯一可靠的方法就是

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

这不合适,您没有调用RemoveMemoryPressure()的好方法。这需要一个终结器,RCW已经有一个终结器,您不能修改它。如果您确信您正确调用了FRCO,那么您只需要更快地处理:)Hans,我们将每个RCW包装在自己的C#对象中,每个C#对象都有一个析构函数。在C#包装器对象中添加内存压力是否合适?我们还实现了Dispose of course,它调用Marshal.finalEleaseComObject。由于我们有一个析构函数,我们可以消除内存压力。如果您确信您正确调用了FRCO,那么您不应该耗尽内存,也不需要GC的帮助。只有在实际内存不足时,才会得到OOM,使用AddMemoryPressure并不能阻止这一点。。如果您不相信,也不应该相信,那么您最好对创建的对象进行引用计数,并以某个值调用GC.Collect()。@HansPassant是否将该注释作为答案发布?保持计数并定期调用GC.Collect+WaitForPendingFinalizers是个好主意。谢谢,Eric。如上所述,我们已经在使用Marshal.ReleaseComObject。我们对“双点”也很小心——也就是说,我们确保释放每个托管引用。我们还知道GC.Collect+GC.WaitForPendingFinalizers会清理它们。但我的问题是在这种情况下使用GC.AddMemoryPressure是否合适,这样我们就不必手动调用GC.Collect+GC.WaitForPendingFinalizers。