我有以下代码块:

IntPtr unmanagedPointer = Marshal.AllocHGlobal(buffer.Length);
Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);
SomeCommandThatCanThrowAnException();
Marshal.FreeHGlobal(unmanagedPointer);

如果在try中包装块,并将freehglobal命令放置在finally块中。(以防中间命令引发异常)。
在这种情况下,似乎最终可以防止内存泄漏,但是从我在网上找到的例子来看,最终没有使用。也许资源无论如何都会被自动释放(即使它们是非托管的)。

最佳答案

使用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中运行良好,完全不需要传递intptr。
safebuffers用于安全地操作c中的非托管内存,因此根据正在执行的操作(分配用于p/invoke的非托管内存,或操作c中的非托管内存),应该适当地选择safehandle或safebuffer作为基类。

09-28 00:06