获取OracleDecimal时存在内存泄漏问题。

5

一年前,@GilShalit发布了一条评论

"好吧,在我们使用ODP(.Net 2.0)处理GetOracleDecimal的代码时,我们因为一个内存泄漏问题(是我们提供给客户的代码)而不再信任它,已经纠结了一年时间...祝好运!" - GilShalit Aug 27 '09 at 12:44

你是如何解决这个问题的呢?

我们有一个服务每隔几分钟会查询Oracle数据库,但是会导致内存无法释放;通过使用WinDbg进行一些调查,我发现在finalize队列中积累了大量的Oracle.DataAccess.Types.OpoDecCtx类型。

以下是我认为存在问题的那行代码:

decimal volume = (decimal)OracleDecimal.SetPrecision(reader.GetOracleDecimal(5), 28);

我将这段代码注释掉后,内存泄漏问题消失了。

如果您有任何想法,请不吝赐教 - 谢谢!


你的问题具体是什么? - Vincent Malgrat
为什么GetOracleDecimal会泄漏内存,我该如何修改已发布的语句以解决这个问题?我希望GilShalit能在这里提供评论,但我很乐意听取任何遇到此问题的人的意见。谢谢。 - Tim
每天都有数千个问题发布,而Gil似乎并不是一个非常频繁的访客。如果你想吸引他的注意,你需要使用@符号,这将显示在他的响应选项卡中。就像这样@GilShalit。 - APC
@APC,谢谢。O @GilShalit,你在哪里? - Tim
改成这样 OracleDecimal.SetPrecision(reader.GetOracleDecimal(5), 28).Value 会有什么不同,而不是强制转换? - V4Vendetta
2个回答

8
这是ODP.NET的一个老问题(参见此处:Memory Problems with ODP.NET 10.1.0.4)。 OracleDecimal类型保存对内部类OpoDecCtx实例的引用。OpoDecCtx实现了IDisposable(因为它本身引用了非托管内存),但由于OracleDecimal没有实现IDisposable,你必须等待垃圾回收器运行以释放底层非托管内存。你可以使用.NET Reflector等工具来检查所有这些内容。
虽然这不是技术上的“物理”内存泄漏(内存最终会被释放),但当你处理大量的OracleDecimal类型实例时,这实际上是一个问题。我不知道为什么Oracle不直接实现IDisposable,这是一件简单的事情……
无论如何,我建议你自己使用反射进行一些hack操作:
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;
}

你可以像这样使用它:

OracleDecimal od = reader.GetOracleDecimal(5);
decimal volume = (decimal)OracleDecimal.SetPrecision(od, 28);
od.Dispose();

在多线程应用程序中,这是一个严重的问题。例如:Oracle实现可能会杀死/阻塞FINALIZER线程,这意味着再也没有需要终结的对象被清理了。 - TomTom
上述解决方案在功能上非常有效,但要注意它会对性能产生相当大的影响。 - tjdecke

0

我不知道是否可能从ODP.NET更改到另一个提供程序,但我们很久以前就解决了这个问题...并且正在使用第三方(商业)ADO.NET提供程序(未关联)...请查看此链接http://www.devart.com/dotconnect/oracle/docs/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接