释放 COM 对象不会影响内存使用情况



当我通过Marshall.ReleaseComObject方法发布com对象时,应用程序的内存使用量不会改变。而不是使用Marshall.ReleaseComObject,使用垃圾收集器(GC.Collect()) 可以释放 com 对象的内存区域,但 UI 越来越慢。

所以我的问题是,释放 com 对象的最佳方法是什么?

虽然有点过时(从 ArcGIS 10.0 开始),但发布规则以及如何执行此操作在 http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#/Releasing_COM_references/0001000004tm000000/上得到了很好的描述。

有两种方法可以做到这一点。要么使用Marshal.ReleaseCOMObject,要么通过使用本质上是前者的包装器的ComReleaser-class。但是,您可能有多个对完全相同的 com-对象的引用,这就是为什么调用ReleaseComObject不会最终释放该对象,而只是将内部引用计数器减少一个。只有当该计数器等于零时,对象才会真正被释放。例如,请参阅此处:

var f1 = featureClass.GetFeature(1);
// retrieve the exact same feature again
var f2 = featureClass.GetFeature(1);

虽然从.NET 透视f1f2是完全不同的对象,底层的 com-对象是相同的(假设唯一实例化,这超出了本问题的范围)。在f1f2上调用Marshal.ReleaseComObject时,您只会将此 com 对象的内部引用计数器减少 1,使一个引用处于活动状态。

但是,GC.Collect没有效果,因为它无法处理 com-object 所在的非托管资源。垃圾回收器只能释放托管资源。因此,调用GC.Collect将仅(如果有的话)释放运行时可调用包装器,该包装器是围绕非托管对象的托管包装器。然而,后者仍然存在于内存中,并且可能会产生死泄漏。

话虽如此,最终释放 com-对象的唯一方法是在循环中调用Marshal.ReleaseComObject,直到引用计数器为零。

while(Marshal.ReleaseComObject(myObject) > 0);

之后,您可能会也可能不会打电话给GC.Collect。但是,我不会建议这样做,因为垃圾收集者最清楚何时释放一个有光泽的物体。强制它这样做充其量只能按预期工作,但最坏的情况是只会让你的代码变慢而没有任何积极的影响。GC是不确定的过程,你不能真正影响它。

最好的方法是使用 ComReleaser 或 Marshal.ReleaseComObject 方法。调用 GC。收集方法过多会导致应用程序变慢。让 GC 在需要时完成其工作。

试试这个,

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oApp);
oApp = null; // Set each COM Object to null
//
// After all of the COM objects have been released and set to null, do the following:
GC.Collect(); // Start .NET CLR Garbage Collection
GC.WaitForPendingFinalizers(); // Wait for Garbage Collection to finish

如果对象实现终结器,调用 gc 意味着将此对象引用放入终结队列中,意味着它不会立即释放。

最新更新