2010-08-04 15 views
5

@GilShalit publicada t his comment a year ago:GetOracleDecimal pérdida de memoria

"Bueno, hemos llegado a desconfiar de PAO (.Net 2.0) después de luchar contra una pérdida de memoria (en código que prestan a un cliente ) en GetOracleDecimal por más de al año ... ¡Buena suerte! " - GilShalit Aug 27 '09 a 12:44

¿Cómo lo resolvió?

Tenemos un servicio que consulta una base de datos Oracle cada pocos minutos que no está liberando memoria; Después de investigar con WinDbg, descubrí que este tipo se está acumulando en la cola de finalización: Oracle.DataAccess.Types.OpoDecCtx.

Aquí está la línea que creo que es el problema:

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

comenté esto y la pérdida de memoria desaparecieron.

Cualquier pensamiento será apreciado, ¡gracias!

+0

¿cuál es exactamente tu pregunta? –

+0

¿Por qué GetOracleDecimal pierde memoria y cómo puedo modificar la declaración publicada para resolver el problema? Esperaba que GilShalit estuviera al acecho aquí y pudiera dar un comentario, pero estoy feliz de saber de alguien que se haya metido en esto. Gracias – Tim

+0

Hay miles de preguntas publicadas todos los días, y no parece que Gil sea un visitante frecuente. Si desea atraer su atención, debe usar el símbolo @, que se mostrará en su pestaña de respuestas. Me gusta @GilShalit – APC

Respuesta

8

Este es un problema antiguo con ODP.NET (ver aquí: Memory Problems with ODP.NET 10.1.0.4).

El tipo OracleDecimal contiene una referencia a una instancia de una clase interna llamada OpoDecCtx. OpoDecCtx implementa IDisposable (ya que se refiere a sí mismo a la memoria no administrada), pero dado que OracleDecimal no implementa IDisposable, tendrá que esperar a que se ejecute el recolector de elementos no utilizados para liberar la memoria subyacente no administrada. Puede verificar todo esto usando una herramienta como .NET Reflector.

Aunque técnicamente no es una pérdida de memoria "física" (la memoria finalmente se liberará), en realidad es un problema cuando se trata de una gran cantidad de instancias del tipo OracleDecimal. No sé por qué Oracle no se limita a implementar IDisposable, es una cosa fácil de hacer ...

De todos modos, yo sugeriría que hacer algún trabajo de corte a sí mismo, utilizando la reflexión:

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

y que le utilizar de esta manera:

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

+1, respuesta sólida! –

+0

es un problema grave en aplicaciones de múltiples hilos.COMO: La implementación de Oracle puede matar/bloquear el hilo de FINALIZER lo que significa que NADA que requiera finalización alguna vez se limpia. – TomTom

+0

La solución anterior funciona muy bien, pero tenga cuidado ya que tiene un impacto bastante significativo en el rendimiento. – tjdecke

0

no sé si es posible cambiar de ODP.NET a otro proveedor, sino que resolvió este problema abandonando PAO hace mucho tiempo ... y están utilizando una 3ra Parte (comercial) Proveedor de ADO.NET (no afiliado) ... consulte este enlace http://www.devart.com/dotconnect/oracle/docs/