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 は非常に強力なため、注意が必要です。
注 2: SafeHandles は P/Invoke とうまく連携し、IntPtrs を完全に渡す必要がなくなります。
SafeBuffers は、C# からアンマネージ メモリを安全に操作するためのものであるため、何を行っているか (P/Invoke で使用するためにアンマネージ メモリを割り当てるか、C# からアンマネージ メモリを操作するか) に応じて、基本クラスとして SafeHandle または SafeBuffer を適切に選択する必要があります。