Dovrebbe Marshal.FreeHGlobal essere collocato in un blocco finally per assicurare le risorse sono disposti?

StackOverflow https://stackoverflow.com/questions/3525932

Domanda

Ho il seguente blocco di codice:

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

Qualora il blocco essere avvolto in una prova, e il comando FreeHGlobal essere collocato in un blocco finally. (Nel caso in cui il comando centrale genera un'eccezione).

E sembra avere senso che finalmente impedirebbe perdite di memoria, in questo caso, però da esempi che ho trovato on-line, infine, non viene utilizzato. Forse le risorse vengono automaticamente eliminati in ogni caso (anche se sono non gestito).

È stato utile?

Soluzione

memoria non gestita allocato con Marshal.AllocHGlobal non viene rilasciato automaticamente.

Quindi, mettendo Marshal.FreeHGlobal in un blocco finally è davvero una buona idea:

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

Gli esempi avete trovato probabilmente Omettere la gestione per brevità di errore.


Se stai allocare memoria non gestita a scopo a lungo termine (cioè non liberandola entro lo stesso metodo), si potrebbe essere interessato a avvolgendo il puntatore in un oggetto che deriva da SafeHandle (come SafeBuffer ).

SafeHandle implementa il pattern IDisposable, così la memoria non gestita verrà liberata quando si deve smaltire l'oggetto o quando il garbage collector raccoglie l'oggetto. SafeHandle anche deriva dalla classe CriticalFinalizerObject che significa che sarà ottenere un trattamento speciale da parte del CLR per assicurarsi che la memoria sia davvero liberata.

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

Esempio:

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

Nota:. SafeBuffer è piuttosto una bestia, quindi si consiglia cautela

Nota 2: SafeHandles funziona bene con P / Invoke e elimina la necessità di passare intorno IntPtrs interamente

.

SafeBuffers sono per la manipolazione in sicurezza memoria non gestita da C #, quindi a seconda di quello che stai facendo (l'allocazione di memoria non gestita per l'utilizzo con P / Invoke, o manipolare memoria non gestita da C #) si dovrebbe scegliere SafeHandle o SafeBuffer come classe base in modo appropriato.

Altri suggerimenti

Assolutamente. E ' non viene rilasciato automaticamente, è memoria non gestita.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top