为什么在手动强制GC执行之前,已发布的ArcObjects COM对象尚未完成?

Gna*_*nat 2 .net com garbage-collection memory-leaks arcobjects

我正在开发一个.NET应用程序,用于处理通过ESRI自己的.NET互操作程序集使用ESRI的ArcObjects COM库的地理数据.

在生产中运行时,由于达到每个进程2GB的内存限制,进程在某些操作期间可能会崩溃.(ArcObjects是一个32位库.)这是因为某些处理步骤可以创建许多临时ArcObjects几何对象.尽管使用FinalReleaseComObject和关联的辅助方法手动释放这些对象,它仍会泄漏内存并最终耗尽内存.但是,我可以强制GC通过调用释放内存WaitForPendingFinalizers,并定期调用它GC.CollectFinalReleaseComObject保持内存使用受控制.否则,许多对象将保留在内存中,直到进程退出(正常或异常).

第一个问题:为什么不立即释放ArcObjects COM对象所占用的内存?或者,为什么GC允许进程崩溃而不是最终确定已发布的COM对象并在崩溃之前回收内存?

该应用程序在Windows 2008 64位上运行,而我使用Windows 7 32位开发.我可以让生产盒上的进程崩溃,但不能在我的开发盒上崩溃.我认为这可能是因为本地我通常在Visual Studio中使用Debug构建运行,但我也尝试使用Release版本而没有调试器(Start Without Debugging),但即便如此,它也没有在任何地方使用内存与生产中一样,不会崩溃.

第二个问题:为什么?

编辑:在我以前的实验中,我发现它GC.Collect本身是不够的,即使我明确地称之为它.我有一个实用程序方法,在每次算法迭代后调用GC.Collect后跟GC.WaitForPendingFinalizers并调用它,以减少内存使用量.

xxb*_*bcc 5

托管应用程序中使用的COM对象位于运行时可调用包装器(RCW)后面,RCW是一个托管对象,它将COM对象的接口复制到托管客户端(它是托管和非托管组件之间的桥梁).如果我没记错的话,实际的COM接口引用由RCW保存,而不是由您的代码保存.当您释放COM对象时,它实际上是已发布的RCW但是,作为一个托管对象本身,在GC到处清理它之前不会消失.当发生这种情况时,RCW被删除,并且对COM对象的最后一次引用消失了,因此它可以自行销毁.(根据文档,FinalReleaseComObject应该将引用计数设置为0,但我在过去看过类似的行为,所以我质疑文档是否正确.)

至于你的第二个问题,我有一个猜测:我在压力环境中看到,当系统负载很重时,GC根本没有机会运行.那时我们确定GC运行在一个优先级较低的线程上,而我们的应用程序使用的CPU太多而GC从未有机会清理.我们不得不添加另一个GC.Collect()每隔一段时间定期调用一次的线程 - 这迫使GC线程唤醒并发挥其魔力.你可能面临类似的事情.(这也可能是你在#1中出现问题的原因.)