c# - 是否应将 Marshal.FreeHGlobal 放在 finally block 中以确保资源得到处理?

标签 c# marshalling finally unmanagedresources

我有以下代码块:

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

是否应该将 block 包裹在 try 中,并将 FreeHGlobal 命令放在 finally block 中。 (以防中间命令抛出异常)。

在这种情况下,finally 似乎可以防止内存泄漏,但是从我在网上找到的示例来看,finally 并没有被使用。也许资源无论如何都会自动处理(即使它们不受管理)。

最佳答案

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

所以将 Marshal.FreeHGlobal 放在 finally block 中确实是个好主意:

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 作为基类。

关于c# - 是否应将 Marshal.FreeHGlobal 放在 finally block 中以确保资源得到处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3525932/

相关文章:

c# - Entity Framework 6 Code-First 级联删除自引用实体

scala - jackson-module-scala (play) : registerModule(DefaultScalaModule): found DefaultScalaModule. 类型;需要 : databind. 模块

xml - JAXB 删除 XmlRootElement 包装器

java - 返回一个可关闭的可迭代对象

c# - 如何发布到 Facebook 用户的个人资料?

c# - Microsoft 如何从 DLL 的元数据中隐藏 C# 内部类?

c# - 为什么 BeforeFieldInit 行为在 .NET 4 中发生了变化?

jaxb - 如何忽略父类中的 JAXB 注释属性?

Java finally block 更改类变量的值,但不更改 Try block 中的 return 语句

java - finally block 和线程挂起