GetOracleDecimal内存泄漏

Tim*_*Tim 5 c# oracle memory-leaks

@GilShalit 一年前发表评论:

"好吧,我们在GetOracleDecimal中对内存泄漏(我们提供给客户的代码中)进行了一年多的打击后,已经开始不信任ODP(.Net 2.0)了......祝你好运!" - GilShalit 09年8月27日12:44

你是怎么解决的?

我们有一个服务,每隔几分钟查询一次没有释放内存的Oracle数据库; 在使用WinDbg进行一些调查之后,我发现这个类型正在最终化队列中堆积:Oracle.DataAccess.Types.OpoDecCtx.

以下是我认为问题的界限:

decimal volume = (decimal)OracleDecimal.SetPrecision(reader.GetOracleDecimal(5), 28);
Run Code Online (Sandbox Code Playgroud)

我评论了这一点,内存泄漏消失了.

任何想法将不胜感激 - 谢谢!

Sim*_*ier 8

这是ODP.NET的一个老问题(参见此处:ODP.NET 10.1.0.4的内存问题).

OracleDecimal类型包含对名为的内部类的实例的引用OpoDecCtx.OpoDecCtx实现IDisposable(因为它本身引用了非托管内存),但由于OracleDecimal没有实现IDisposable,所以你必须等待垃圾收集器运行以释放底层的非托管内存.您可以使用.NET Reflector等工具检查所有这些.

虽然从技术上讲它不是"物理"内存泄漏(内存最终会被释放),但是当你处理大量OracleDecimal类型的实例时,它实际上是一个问题.我不知道为什么Oracle不会简单地实现IDisposable,这是一件简单的事情......

无论如何,我建议你自己做一些黑客工作,使用反射:

public static class OracleExtentions
{
    public static void Dispose(this OracleDecimal od) // build an extension method
    {
        if (OracleDecimalOpoDecCtx == null)
        {
            // cache the data
            // get the underlying internal field info
            OracleDecimalOpoDecCtx = typeof(OracleDecimal).GetField("m_opoDecCtx", BindingFlags.Instance | BindingFlags.NonPublic);
        }
        IDisposable disposable = OracleDecimalOpoDecCtx.GetValue(od) as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }

    private static FieldInfo OracleDecimalOpoDecCtx;
}
Run Code Online (Sandbox Code Playgroud)

你会像这样使用它:

OracleDecimal od = reader.GetOracleDecimal(5);
decimal volume = (decimal)OracleDecimal.SetPrecision(od, 28);
od.Dispose();
Run Code Online (Sandbox Code Playgroud)