【问题标题】:Why are released ArcObjects COM objects not finalized until the GC is manually forced to do so?为什么在手动强制 GC 完成之前释放的 ArcObjects COM 对象没有最终确定?
【发布时间】:2012-09-28 06:16:51
【问题描述】:

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

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

第一个问题:为什么 ArcObjects COM 对象持有的内存没有立即释放?或者,为什么 GC 允许进程崩溃,而不是在崩溃之前完成释放的 COM 对象并回收内存?

该应用程序在 Windows 2008 64 位的生产环境中运行,而我使用 Windows 7 32 位进行开发。我可以让进程在生产盒上崩溃,但不能在我的开发盒上崩溃。我认为这可能是因为我通常在本地使用 Debug 版本在 Visual Studio 中运行,但我也使用 Release 版本在没有调试器的情况下尝试过(不使用调试启动),但即便如此,它也没有使用任何地方。内存在生产中,不会崩溃。

第二个问题:为什么?

编辑:在我之前的实验中,我发现 GC.Collect 本身是不够的,即使我明确地调用它。我有一个实用方法,它调用GC.Collect,后跟GC.WaitForPendingFinalizers,并在每次算法迭代后调用它可以降低内存使用率。

【问题讨论】:

    标签: .net com memory-leaks garbage-collection arcobjects


    【解决方案1】:

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

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

    【讨论】:

    • 我确实知道 RCW 等等,但是尽管 GC 显式运行,但 COM 对象持有的内存并未被释放。我已经更新了问题。
    • @Gnat 您需要GC.WaitForPendingFinalizers() 的原因是因为GC.Collect() 实际上并不运行GC。它要求 GC 执行一个收集周期,但 GC 在不同的线程上运行,并且可能不会在重负载下被调度。 GC.WaitForPendingFinalizers() 强制等待直到下一个收集周期结束 - 这会释放 CPU 并且 GC 有机会运行并完成内存清理。
    • @Gnat 如果您询问是否需要调用GC.WaitForPendingFinalizers() 是否正确(或预期),那么是的,如果您的应用程序对 CPU 造成负载,则可以预期。在高负载、高内存的情况下,GC 线程可能会饿死,系统(或进程)可能会耗尽内存。我必须在我提到的那个旧项目中做同样的事情。
    • 我已经进行了一些挖掘,看来您可能是对的。该进程在工作站 GC 模式下运行(至少在本地),msdn.microsoft.com/en-us/library/… 表示 GC 线程必须竞争 CPU 并且具有本机代码的线程(即应用​​程序正在执行的大部分操作)不会暂停。各种资源(例如msdn.microsoft.com/en-us/library/ff647812.aspxstackoverflow.com/questions/12265598)说等待终结者是个坏主意,但我看不到解决办法。
    • 由于解释性 cmets 被接受为答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-06
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 2012-08-24
    相关资源
    最近更新 更多