2010-08-19 69 views
5

我有下面的代码块:Marshal.FreeHGlobal应该放在finally块中以确保资源被丢弃吗?

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

如果该块被包裹在一试,和FreeHGlobal命令被放置在最后块。 (如果中间命令引发异常)。

似乎有意义的是,在这种情况下最终会防止内存泄漏,但是从我在网上找到的例子中,终于没有被使用。无论如何,资源可能会自动处理(尽管它们是非托管的)。

回答

12

未分配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#中的非托管内存。 。

2

绝对如此。它从来没有自动释放,它是非托管内存。

相关问题