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 .