Niezarządzana pamięć przydzielona z Marshal.AllocHGlobal nie jest automatycznie zwolniona.
więc oddanie Marshal.FreeHGlobal w finally
bloku jest rzeczywiście dobry pomysł:
IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
try
{
Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
SomeCommandThatCanThrowAnException();
}
finally
{
Marshal.FreeHGlobal(unmanagedPointer);
}
W znalazłeś zapewne przykłady pominąć błąd obsługi dla zwięzłości.
Jeśli przydzielania pamięci niezarządzanej do celów długoterminowych (tj nie zwalniając go w tej samej metody), może być zainteresowany owijania wskaźnik w obiekcie, który wywodzi się z SafeHandle (takich jak SafeBuffer) .
SafeHandle implementuje wzorzec IDisposable, dzięki czemu pamięć niezarządzana zostanie zwolniona po usunięciu obiektu lub gdy zbierający śmieci zbiera obiekt. SafeHandle wywodzi się również z klasy CriticalFinalizerObject, co oznacza, że otrzyma specjalne traktowanie od CLR, aby upewnić się, że pamięć jest naprawdę uwolniona.
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;
}
}
Przykład:
using (var h = new HGlobal(buffer.Length))
{
h.WriteArray(0, buffer, 0, buffer.Length);
}
Uwaga: SafeBuffer jest dość bestią, więc należy zachować ostrożność.
Uwaga 2: SafeHandles działa dobrze z P/Invoke i eliminuje potrzebę całkowitego omijania IntPtrs.
SafeBuffery służą do bezpiecznego manipulowania niezarządzaną pamięcią z C#, więc w zależności od tego, co robisz (przydzielanie niezarządzanej pamięci do użycia z P/Invoke lub manipulowanie niezarządzaną pamięcią z C#), należy odpowiednio wybrać SafeHandle lub SafeBuffer jako klasę podstawową .