【问题标题】:Memory leak in .NET Garbage Collector with System.Transactions.SafeIUnknownSystem.Transactions.SafeIUnknown 的 .NET 垃圾收集器中的内存泄漏
【发布时间】:2010-03-04 11:51:06
【问题描述】:

我正在尝试使用 ANTS 分析器跟踪应用程序中的内存泄漏。我追踪到垃圾收集器,我们有一个 System.Transactions.SafeIUnknown 对象列表,这些对象永远存在于垃圾收集器中,在终结器队列中但从未被释放。

我无法在 System.Transactions.SafeIUnknown 上找到任何文档,也无法确定将创建或引用它的内容,这不是我们故意的。

我希望那里的人可能对此有所了解。这是 20 字节的小泄漏,但是当我们的应用程序连续运行数天时,泄漏就会累积,我们有数百万个等待最终确定的数据,它开始消耗大量内存。

有人知道从这里去哪里吗?

跟进

我已将其追踪到正在使用的特定库。在我们通过这个特定的库执行任何 SQL 语句后,它似乎被抛在了后面。语句没有包装在事务中,但它们是通过一个相当复杂的循环执行的,泛型类型和目前看起来像双三重间接的方式,委托被传递以进行运动并包装在可以包装在更多闭包中的闭包中。 我会继续尝试准确地把它固定下来,我的第一个停靠点是尝试看看我是否可以使用类似的机制来重现它。

【问题讨论】:

    标签: c# .net memory-leaks


    【解决方案1】:

    SafeIUnknown 派生自 SafeHandle。那是实现终结器的类。它很特别,它的终结代码运行在关键执行区(CER)中。这种代码提供了执行保证,异常被抑制。终结器运行 SafeIUnknown.ReleaseHandle(),它调用 Marshal.Release() 以释放由 SafeIUnknown 包装的 COM 接口指针。

    在终结队列中看到大量此类包装器表明 Marshal.Release() 调用正在引发异常。防止包装器最终确定。找出它抛出异常的确切原因将是一件棘手的事情。这是非托管代码轰炸,您几乎没有任何提示可以找出原因。 95% 的情况是堆损坏,这是一个很难解决的问题。最重要的是,这可能不是您的代码,而且您没有任何来源。

    您应该能够在良好的非托管代码调试器(如 WinDbug)中在第一次出现异常时获得断点。获取调试符号对于理解堆栈跟踪至关重要。然而,从那里可能仍然是一个很长的镜头。考虑从 Microsoft 支持获得帮助。或者像重建机器这样的剧烈运动。祝你好运!

    【讨论】:

    • 非常感谢您的评论。会继续调查,看看我能去哪里。
    【解决方案2】:

    SafeIUnknown 源自 System.Transactions 中的一些方法,其中之一是 TransactionScope 构造函数和 Dispose 方法。对这些的调用最终在称为 JitSafeGetContextTransactionTransaction 类上的内部方法中结束,该方法进一步调用本机 Ole32 函数 CoGetDefaultContext,该函数返回 SafeIUnknown 的实例。

    这暗示有问题的对象与您的事务上下文的内部表示有关。

    可能是您没有正确释放事务或事务范围吗?如果是这样,您使用的数据提供程序可能存在问题?

    【讨论】:

    • 非常感谢 Peter 在之前的评论中提到的评论,我会继续调查,看看我能去哪里。
    • 顺便说一句,它是我正在使用的 MS SQL 数据提供程序。
    猜你喜欢
    • 2018-05-10
    • 2012-01-03
    • 1970-01-01
    • 2012-06-28
    • 1970-01-01
    • 1970-01-01
    • 2016-11-02
    • 2012-05-21
    • 2011-02-12
    相关资源
    最近更新 更多