See the question and my original answer on StackOverflow

This is an old issue with ODP.NET (see here: Memory Problems with ODP.NET 10.1.0.4 ).

The OracleDecimal type holds a reference to an instance of an internal class named OpoDecCtx. OpoDecCtx implements IDisposable (as it's itself referencing unmanaged memory), but since OracleDecimal does not implement IDisposable, you'll have to wait for the garbage collector to run to free the underlying unmanaged memory. You can check all this using a tool such as .NET Reflector.

Although it's not technically a "physical" memory leak (memory will be eventually freed), it is actually a problem when you're dealing with a large amount of instances of the OracleDecimal type. I don't know why Oracle does not simply implement IDisposable, it's a simple thing to do...

Anyway, I suggest you do some hack job yourself, using reflection:

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;
}

And you would use it like this:

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