2010-08-19 27 views
5

Tôi có khối mã sau đây:Nên Marshal.FreeHGlobal được đặt trong một khối cuối cùng để đảm bảo nguồn lực được xử lý?

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

khối nên được bọc trong một thử, và lệnh FreeHGlobal được đặt trong một khối finally. (Trong trường hợp lệnh giữa ném một ngoại lệ).

Có vẻ như có ý nghĩa rằng cuối cùng sẽ ngăn chặn rò rỉ bộ nhớ trong trường hợp này, tuy nhiên từ các ví dụ mà tôi đã tìm thấy trực tuyến, cuối cùng không được sử dụng. Có lẽ các tài nguyên được tự động xử lý anyway (mặc dù chúng không được quản lý).

Trả lời

12

Bộ nhớ không được quản lý được cấp phát bằng Marshal.AllocHGlobal không được tự động phát hành.

Vì vậy, việc đưa Marshal.FreeHGlobal trong một khối finally thực sự là một ý tưởng tốt:

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

Các ví dụ bạn đã tìm thấy lẽ bỏ qua lỗi xử lý cho ngắn gọn.


Nếu bạn đang phân bổ bộ nhớ không được quản lý cho mục đích dài hạn (tức là không giải phóng nó trong cùng một phương pháp), bạn có thể quan tâm gói con trỏ ở một đối tượng mà xuất phát từ SafeHandle (như SafeBuffer) .

SafeHandle triển khai mẫu IDisposable, do đó bộ nhớ không được quản lý sẽ được giải phóng khi bạn vứt bỏ đối tượng hoặc khi bộ thu gom rác thu thập đối tượng. SafeHandle cũng xuất phát từ lớp CriticalFinalizerObject có nghĩa là nó sẽ được xử lý đặc biệt từ CLR để đảm bảo bộ nhớ thực sự được giải phóng.

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; 
    } 
} 

Ví dụ:

using (var h = new HGlobal(buffer.Length)) 
{ 
    h.WriteArray(0, buffer, 0, buffer.Length); 
} 

Lưu ý: SafeBuffer là khá một con thú, vì vậy cần thận trọng.

Lưu ý 2: SafeHandles hoạt động tốt với P/Invoke và loại bỏ sự cần thiết phải vượt qua toàn bộ IntPtrs. SafeBuffer là để thao tác một cách an toàn bộ nhớ không được quản lý từ C#, do đó tùy thuộc vào những gì bạn đang làm (phân bổ bộ nhớ không được quản lý để sử dụng với P/Invoke, hoặc thao tác bộ nhớ không được quản lý từ C#), bạn nên chọn SafeHandle hoặc SafeBuffer làm lớp cơ sở một cách thích hợp .

2

Tuyệt đối. Nó không bao giờ được phát hành tự động, nó là bộ nhớ không được quản lý.

Các vấn đề liên quan