释放Com对象不会影响内存使用

时间:2018-01-05 08:26:29

标签: c# .net garbage-collection arcgis arcobjects

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

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

4 个答案:

答案 0 :(得分:1)

尽管有点过时(从ArcGIS 10.0开始),http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#/Releasing_COM_references/0001000004tm000000/上已经详细描述了发布规则以及如何执行此操作。

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

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

虽然从.NET角度来看f1f2是完全不同的对象,但底层的com对象是相同的(假设是唯一实例,这超出了本问题的范围) 。在Marshal.ReleaseComObjectf1上调用f2时,您只会将此com对象的内部引用计数器减一,使一个引用保持活动状态。

然而,

GC.Collect无效,因为它无法处理com-objects所属的非托管资源。垃圾收集器只能释放托管的资源。因此,调用GC.Collect只会 - 如果有的话 - 释放运行时可调用包装器,它是非托管对象周围的托管包装器。然而,后者仍然存在于记忆中并且很可能产生死漏。

说完最终发布com-objects的唯一方法是在循环中调用Marshal.ReleaseComObject,直到引用计数器为零。

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

之后您可能会或可能不会致电GC.Collect。但是我不建议这样做,因为垃圾收集器知道什么时候释放一个管理对象。强制它这样做最多只能按预期工作,但最糟糕的是,只有在没有任何积极影响的情况下才能减慢代码速度。 GC是不确定的过程,你不能真正影响它。

答案 1 :(得分:0)

试试这个,

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

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