当我通过Marshall.ReleaseComObject方法释放com对象时,应用程序的内存使用量不会改变。而不是使用Marshall.ReleaseComObject,使用垃圾收集器(GC.Collect())可以释放com对象的内存区域,但UI正在变慢。
所以我的问题是,释放com对象的最佳方法是什么?
答案 0 :(得分:1)
尽管有点过时(从ArcGIS 10.0开始),http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#/Releasing_COM_references/0001000004tm000000/上已经详细描述了发布规则以及如何执行此操作。
有两种方法可以做到这一点。通过使用Marshal.ReleaseCOMObject
或ComReleaser
- 类,它基本上是前者的包装器。但是,您可能对完全相同的com对象有多个引用,这就是为什么调用ReleaseComObject
不会最终释放对象,而只是将内部引用计数器减少一个。只有当该计数器等于零时,对象才会实际被释放。请参见此处:
var f1 = featureClass.GetFeature(1);
// retrieve the exact same feature again
var f2 = featureClass.GetFeature(1);
虽然从.NET角度来看f1
和f2
是完全不同的对象,但底层的com对象是相同的(假设是唯一实例,这超出了本问题的范围) 。在Marshal.ReleaseComObject
或f1
上调用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在需要时完成其工作。