Неуправляемая память, выделенная с помощью Marshal.AllocHGlobal, не освобождается автоматически.
Поэтому размещение Marshal.FreeHGlobal в блоке finally
действительно хорошая идея:
IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
try
{
Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
SomeCommandThatCanThrowAnException();
}
finally
{
Marshal.FreeHGlobal(unmanagedPointer);
}
Примеры, которые выВозможно, вы обнаружили, что для краткости опущена обработка ошибок.
Если вы выделяете неуправляемую память для долгосрочных целей (т.е. не освобождаете ее в том же методе), вас может заинтересовать перенос указателяв объекте, который является производным от SafeHandle (например, SafeBuffer ).
SafeHandle реализует шаблон IDisposable, поэтому неуправляемая память будет освобожденакогда вы утилизируете объект или когда сборщик мусора собирает объект.SafeHandle также является производным от класса CriticalFinalizerObject, что означает, что он получит специальную обработку от CLR, чтобы убедиться, что память действительно освобождена.
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;
}
}
Пример:
using (var h = new HGlobal(buffer.Length))
{
h.WriteArray(0, buffer, 0, buffer.Length);
}
Примечание: SafeBuffer isэто чудовище, поэтому рекомендуется соблюдать осторожность.
Примечание 2. SafeHandles хорошо работают с P / Invoke и устраняют необходимость полностью обойти IntPtrs.
SafeBuffers предназначены для безопасного манипулирования неуправляемой памятью из C #поэтому, в зависимости от того, что вы делаете (выделяя неуправляемую память для использования с P / Invoke или манипулируя неуправляемой памятью из C #), вы должны выбрать SafeHandle или SafeBuffer в качестве базового класса соответственно.