@GilShalit posted this comment a year ago:
"Well, we have come to distrust ODP (.Net 2.0) after fighting a memory leak (in code we supplied to a customer) in GetOracleDecimal for over a year... Good luck!" – GilShalit Aug 27 '09 at 12:44
How did you solve it?
We have a service that queries an Oracle database every few minutes that is not releasing memory; after some investigation using WinDbg I discovered that this type is piling up in the finalize queue: Oracle.DataAccess.Types.OpoDecCtx.
Here's the line that I think is the problem:
decimal volume = (decimal)OracleDecimal.SetPrecision(reader.GetOracleDecimal(5), 28);
I commented this out and the memory leak disappeared.
Any thoughts will be appreciated - thanks!
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With