2010-08-19 5 views
5

J'ai le bloc de code suivant:Marshal.FreeHGlobal doit-il être placé dans un bloc finally pour s'assurer que les ressources sont éliminées?

IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length); 
Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length); 
SomeCommandThatCanThrowAnException(); 
Marshal.FreeHGlobal(unmanagedPointer); 

Si le bloc envelopper dans un essai, et la commande FreeHGlobal être placé dans un bloc finally. (Au cas où la commande du milieu lève une exception).

Il semble logique que finalement empêcherait les fuites de mémoire dans ce cas, mais à partir d'exemples que j'ai trouvé en ligne, n'est finalement pas utilisé. Peut-être que les ressources sont automatiquement éliminées de toute façon (même si elles ne sont pas gérées).

Répondre

12

La mémoire non gérée allouée avec Marshal.AllocHGlobal n'est pas libérée automatiquement.

Donc, mettre Marshal.FreeHGlobal dans un bloc finally est en effet une bonne idée:

IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length); 
try 
{ 
    Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length); 
    SomeCommandThatCanThrowAnException(); 
} 
finally 
{ 
    Marshal.FreeHGlobal(unmanagedPointer); 
} 

Les exemples que vous avez trouvé omettent probablement erreur de manipulation par souci de concision.


Si vous allouer de la mémoire à des fins non géré à long terme (c.-à-pas le libérer dans le même méthode), vous pourriez être intéressé par envelopper le pointeur dans un objet qui dérive de SafeHandle (comme SafeBuffer) .

SafeHandle implémente le modèle IDisposable, de sorte que la mémoire non managée sera libérée lorsque vous disposez de l'objet ou lorsque le garbage collector collecte l'objet. SafeHandle dérive également de la classe CriticalFinalizerObject ce qui signifie qu'il recevra un traitement spécial du CLR pour s'assurer que la mémoire est réellement libérée.

class HGlobal : SafeBuffer 
{ 
    public HGlobal(int cb) 
     : base(true) 
    { 
     this.SetHandle(Marshal.AllocHGlobal(cb)); 
     this.Initialize((ulong)cb); 
    } 

    protected override bool ReleaseHandle() 
    { 
     Marshal.FreeHGlobal(this.handle); 
     return true; 
    } 
} 

Exemple:

using (var h = new HGlobal(buffer.Length)) 
{ 
    h.WriteArray(0, buffer, 0, buffer.Length); 
} 

Note: SafeBuffer est tout à fait une bête, si la prudence est conseillée.

Remarque 2: SafeHandles fonctionne bien avec P/Invoke et élimine le besoin de contourner complètement IntPtrs. Les SafeBuffers sont conçus pour manipuler en toute sécurité de la mémoire non managée à partir de C#, donc en fonction de ce que vous faites (allouer de la mémoire non managée à P/Invoke ou manipuler de la mémoire non managée), vous devez choisir SafeHandle ou SafeBuffer comme classe de base. .

2

Absolument. Il jamais obtient libéré automatiquement, il est une mémoire non gérée.

Questions connexes