Marshal.FreeHGlobal应该放在finally块中以确保资源处置?

vic*_*csz 6 c# finally marshalling unmanagedresources

我有以下代码块:

IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
SomeCommandThatCanThrowAnException();
Marshal.FreeHGlobal(unmanagedPointer);
Run Code Online (Sandbox Code Playgroud)

是否应该在try中包装块,并将FreeHGlobal命令放在finally块中.(如果middle命令抛出异常).

在这种情况下最终会防止内存泄漏似乎是有道理的,但是从我在网上找到的例子中,最终没有使用.也许资源会被自动处理掉(即使它们是不受管理的).

dtb*_*dtb 13

分配给Marshal.AllocHGlobal的非托管内存不会自动释放.

所以把Marshal.FreeHGlobal放在一个finally区块中确实是一个好主意:

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

您找到的示例可能会省略错误处理以简化操作.


如果您为长期目的分配非托管内存(即不在同一方法中释放它),您可能有兴趣将指针包装在派生自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;
    }
}
Run Code Online (Sandbox Code Playgroud)

例:

using (var h = new HGlobal(buffer.Length))
{
    h.WriteArray(0, buffer, 0, buffer.Length);
}
Run Code Online (Sandbox Code Playgroud)

注意:SafeBuffer是一个野兽,所以建议谨慎.

注2:SafeHandles与P/Invoke配合良好,无需完全传递IntPtrs.

SafeBuffers用于从C#安全地操作非托管内存,因此根据您正在做的事情(分配非托管内存以用于P/Invoke,或者从C#操作非托管内存),您应该选择SafeHandle或SafeBuffer作为基类.