2010-08-04 10 views
5

@GilShalit affiché t his comment a year ago:GetOracleDecimal fuite de mémoire

« Eh bien, nous sommes venus à se méfier ODP (.Net 2.0) après avoir combattu une fuite mémoire (dans le code, nous avons fourni à un client ) dans GetOracleDecimal pour plus de par an ... Bonne chance! " - GilShalit août 27 09 à 12:44

Comment avez-vous le résoudre?

Nous avons un service qui interroge une base de données Oracle toutes les quelques minutes qui ne libère pas de mémoire; après une enquête utilisant WinDbg, j'ai découvert que ce type s'accumule dans la file d'attente de finalisation: Oracle.DataAccess.Types.OpoDecCtx.

est ici la ligne que je pense est le problème:

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

j'ai fait remarquer cela et la fuite de mémoire disparaissaient.

Toutes les pensées seront appréciées - merci!

+0

Quelle est précisément votre question? –

+0

Pourquoi GetOracleDecimal fuit-il la mémoire et comment puis-je modifier l'instruction affichée pour résoudre le problème? J'espérais que GilShalit serait caché ici et pourrait fournir des commentaires, mais je suis heureux d'avoir des nouvelles de tous ceux qui y sont confrontés. Merci – Tim

+0

Il ya des milliers de questions postées chaque jour, et il ne semble pas que Gil soit un visiteur très fréquent. Si vous voulez attirer son attention, vous devez utiliser le symbole @, qui apparaîtra dans son onglet Réponses. Comme ceci @GilShalit – APC

Répondre

8

Ceci est un ancien problème avec ODP.NET (voir ici: Memory Problems with ODP.NET 10.1.0.4).

Le type OracleDecimal contient une référence à une instance d'une classe interne nommée OpoDecCtx. OpoDecCtx implémente IDisposable (comme il fait lui-même référence à la mémoire non gérée), mais comme OracleDecimal n'implémente pas IDisposable, vous devrez attendre que le garbage collector s'exécute pour libérer la mémoire non managée sous-jacente. Vous pouvez vérifier tout cela en utilisant un outil tel que .NET Reflector.

Bien que ce ne soit pas techniquement une fuite de mémoire "physique" (la mémoire sera éventuellement libérée), c'est en fait un problème quand vous traitez une grande quantité d'instances du type OracleDecimal. Je ne sais pas pourquoi Oracle ne met pas en œuvre simplement IDisposable, il est une chose simple à faire ...

Quoi qu'il en soit, je vous suggère de faire un certain travail hack vous, en utilisant la réflexion:

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

et que vous l'utiliser comme ceci:

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

+1, réponse solide! –

+0

c'est un problème sérieux dans les applications multi-thread.AS IN: oraclesi mplementation peut tuer/bloquer le thread FINALIZER ce qui signifie que RIEN exigeant la finalisation ne sera plus nettoyé. – TomTom

+0

La solution ci-dessus fonctionne très bien, mais attention car elle a un impact significatif sur les performances. – tjdecke

0

Je ne sais pas s'il est possible de changer de ODP.NET à un autre fournisseur, mais nous avons résolu ce problème en amerrissage ODP il y a longtemps ... et utilisent un une 3e fournisseur (commercial) ADO.NET (non affilié) ... vérifier ce lien http://www.devart.com/dotconnect/oracle/docs/