2010-08-19 664 views
5

Tengo el siguiente bloque de código:¿Debería colocarse Marshal.FreeHGlobal en un bloque final para garantizar la eliminación de los recursos?

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

caso de que el bloque de ser envuelto en un intento, y el comando FreeHGlobal ser colocado en un bloque finally. (En caso de que el comando central arroje una excepción).

Parece que tiene sentido que finalmente evitaría fugas de memoria en este caso, sin embargo, de los ejemplos que he encontrado en línea, finalmente no se utiliza. Tal vez los recursos se eliminen automáticamente de todos modos (aunque no estén administrados).

Respuesta

12

La memoria no administrada asignada con Marshal.AllocHGlobal no se libera automáticamente.

Así que poner Marshal.FreeHGlobal en un bloque finally es de hecho una buena idea:

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

Los ejemplos que has encontrado probablemente omitir el tratamiento de errores por razones de brevedad.


Si va a asignar memoria no administrado con fines a largo plazo (es decir, no liberándolo dentro del mismo método), que podría estar interesado en envolver el puntero en un objeto que se deriva de SafeHandle (como SafeBuffer) .

SafeHandle implementa el patrón IDisposable, por lo que la memoria no administrada se liberará cuando disponga del objeto o cuando el recolector de basura recoja el objeto. SafeHandle también se deriva de la clase CriticalFinalizerObject lo que significa que recibirá un trato especial del CLR para asegurarse de que la memoria realmente se libera.

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

Ejemplo:

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

Nota: SafeBuffer es bastante bestia, por lo que se recomienda precaución.

Nota 2: SafeHandles funciona bien con P/Invoke y elimina la necesidad de pasar por todo IntPtrs.

SafeBuffers son para manipular memoria no administrada desde C#, por lo que dependiendo de lo que esté haciendo (asignando memoria no administrada para P/Invoke, o manipulando memoria no administrada de C#) debe elegir SafeHandle o SafeBuffer como clase base apropiadamente .

2

Absolutamente. Es nunca se libera automáticamente, es la memoria no administrada.

Cuestiones relacionadas