代码之家  ›  专栏  ›  技术社区  ›  Abhinav Galodha

托管+非托管应用程序导致内存泄漏

  •  0
  • Abhinav Galodha  · 技术社区  · 15 年前

    我在COM组件(使用VB6创建)上有一个包装管理的应用程序(.NET),其中COM组件也使用本机C++ DLL。

    应用程序作为后台进程运行,应该连续运行24 x 7。 应用程序在一定时间内运行良好,但在一定时间后会崩溃。 可能的原因可能是C++DLL或COM组件中的MMORION泄漏。COM和C++的DLL有很多代码。

    由于我不熟悉COM和C++,所以我试图从托管应用程序中解决这个问题。我正在考虑用这种方式解决问题:如果托管应用程序开始消耗大量内存,那么我将重新启动托管应用程序。

    1)我们如何通过编程监控应用程序(托管+非托管)使用的总内存。

    2)重新启动托管应用程序也会释放非托管资源。

    3)是否有其他替代方法。

    4)哪些是监控也使用非托管资源的托管应用程序的最佳调试工具。

    如果我的解释不清楚,那就再问我一次。

    任何帮助都将不胜感激。

    1 回复  |  直到 11 年前
        1
  •  1
  •   Richard    11 年前

    我们如何通过编程监控应用程序(托管+非托管)使用的总内存。

    使用性能计数器。在最容易使用的开发/测试中 PerfMon 在后台收集数据(使用数据收集集),然后用Excel或类似软件分析结果。

    如果您需要在生产使用中继续这样做,应用程序可以读取性能计数器本身(使用 System.Diagnostics.PerformanceCounter 以及相关的课程)。

    2)重新启动托管应用程序也会释放非托管资源。

    对。

    3)是否有其他替代方法。

    是:解决问题。

    如果COM组件或C++库真的泄漏,那么那些确实需要修复(如果以前只用于短时间进程,泄漏可能已经存在很长时间了)。

    您可能正在使用本机堆与.NET托管堆和GC进行交互。当存在内存压力时,托管GC将运行(即,否则需要为进程获取更多内存以完成分配)。如果托管包装器没有分配内存(或者没有太多内存),那么它就没有理由运行GC。当您从.NET引用COM组件时,引用被保存在本机包装类型中,当GC收集COM实例时,此包装将释放该实例(通过释放最后计数的COM引用)。

    因此,如果GC不运行,则不会释放COM组件。只需COM实例使用大量内存,整个进程内存提交就可以开始增长。

    有三种方法(降低偏好):

    1. 使用COM实例上的方法释放其内存使用(例如释放子对象)(如果有)。
    2. 托管代码完成后显式释放COM组件实例,不要等待GC使用 Marshal.ReleaseComObject .
    3. 强制GC。

    #3是最简单的方法,可以在运行几个小时(例如在计时器上)并查看内存使用性能计数器后强制完全GC来确认这种方法。如果是这种情况,则继续执行1或2。

    (这基本上是在我的第一个.NET项目中发生的事情,大量非托管堆的交互无法被由于缺少托管内存压力而未收集的托管实例释放。在这种情况下,修复方法是向键COM组件添加一个额外的方法,以释放它所持有的对象。)