未分配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。你可以选择SafeHandle或SafeBuffer作为基类,它可以根据你正在做的事情(分配非托管内存用于P/Invoke,或者从C#操作非托管内存),安全地操作C#中的非托管内存。 。
来源
2010-08-19 20:38:55
dtb