2009-03-26 4 views
9

Tôi có một đối tượng COM giả với chữ ký sauC# có làm sạch bộ nhớ phân bổ C++ không?

void MemAlloc(ref double[] test, int membercount) 

nơi bộ nhớ được phân bổ trong C++ sử dụng mới/malloc. Một khi điều này là trong C#, bằng cách sử dụng RCW, làm thế nào để đảm bảo rằng bộ nhớ được giải phóng một cách chính xác? Tôi sẽ nghĩ rằng nó sẽ là khó khăn cho. NET miễn phí, xem xét trong C + +, bạn cần phải biết nếu nó đã được phân bổ với new/malloc/mm_malloc trước khi bạn có thể giải phóng nó một cách chính xác. Vì vậy, cách appopriate để làm sạch mảng C + + phân bổ của tôi là gì? Cảm ơn.

Trả lời

8

Tôi tin rằng bạn nên sử dụng CoTaskMemAlloc() cho bộ nhớ mà bạn muốn rõ ràng miễn phí từ phía được quản lý. CLR sẽ xử lý việc giải phóng bộ nhớ khi nó không thể truy cập được nữa. Nếu bạn muốn giải phóng nó một cách rõ ràng, bạn có thể sử dụng quy trình Marshal.CoTaskFree() được quản lý.

Nói chung, trình so khớp interop và CLR tuân thủ các quy ước COM để giải phóng bộ nhớ; người nhận chịu trách nhiệm giải phóng bộ nhớ. Vì vậy, các CLR/Interop marshaler thường sẽ chăm sóc giải phóng bộ nhớ được phân bổ trong một cuộc gọi bản địa nếu bộ nhớ đó được trả lại cho người gọi được quản lý.

Từ Memory Management with the Interop Marshaler (MSDN):

Các marshaler interop luôn cố gắng vào bộ nhớ được cấp phát bởi không được quản lý mã. Hành vi này tuân thủ các quy tắc quản lý bộ nhớ COM , nhưng khác với từ các quy tắc chi phối native C++.

Lẫn lộn có thể xảy ra nếu bạn dự đoán bản C++ hành vi (không có ký ức giải phóng) khi sử dụng nền tảng invoke, tự động giải phóng bộ nhớ cho con trỏ . Ví dụ: gọi phương thức không được quản lý sau từ C++ DLL không tự động giải phóng bất kỳ bộ nhớ nào.

Thời gian chạy luôn sử dụng phương pháp CoTaskMemFree để giải phóng bộ nhớ. Nếu bộ nhớ bạn đang làm việc là không được phân bổ với phương pháp CoTaskMemAlloc , bạn phải sử dụng IntPtr và miễn phí bộ nhớ theo cách thủ công bằng phương pháp thích hợp .

+0

cảm ơn, đó là chính xác những gì tôi đang tìm kiếm – Steve

6

Gói nó vào một đối tượng triển khai IDisposable và đảm bảo rằng trình bao bọc C# được xử lý.

Here's a blog I wrote về cách dễ dàng để triển khai IDisposable.

+0

Sử dụng IDisposable là một chiến lược quản lý tài nguyên tốt, nhưng làm thế nào để bạn triển khai phương pháp Vứt bỏ để thực sự giải phóng bộ nhớ? –

1

Tôi gần như chắc chắn 100% CLR sẽ không tự động giải phóng bộ nhớ được cấp phát cho thử nghiệm (nếu là PInvoke tôi chắc chắn 100%). Lý do là, làm thế nào để CLR biết những gì bạn đã sử dụng để phân bổ bộ nhớ ở nơi đầu tiên? Cụ thể là không.

Một cách an toàn hơn để viết chức năng này như sau

void MemAlloc(ref IntPtr arrayPtr, int membercount) 

khi bạn nhận được cuộc gọi trở lại, bạn có thể làm như sau.

var count = GetTheCount(); 
var arrayPtr = IntPtr.Zero; 
obj.MemAlloc(ref arrayPtr, count); 
byte[] test = MarshalThePtrToByteArray(arrayPtr, count); 
Marshal.FreeCoTaskMem(arrayPtr); 

Đây là một thực hiện nhanh chóng và dơ bẩn của MarashalThePtrToByteArray

byte[] MarashalThePtrToByteArray(IntPtr ptr, int count) { 
    byte[] arr = new byte[count]; 
    for (int i = 0; i < count; i++) { 
    arr[i] = (byte)Marshal.PtrToStructure(ptr, typeof(byte)); 
    ptr = new IntPtr(IntPtr.ToInt64() + Marshal.SizeOf(typeof(byte))); 
    } 
    return arr; 
} 
+0

Đối với COM Interop trình tự sắp xếp CLR/Interop sử dụng quy ước COM của bộ nhớ giải phóng được trả về cho người gọi miễn là bộ nhớ được cấp phát với CoTaskMemAlloc(). –

+0

@Arnshea, nhưng làm thế nào để CLR biết được phân bổ với CoTaskMemAlloc? Nó không thể và nhiều triển khai COM không sử dụng CoTaskMemAlloc cho dữ liệu. – JaredPar

+0

Đúng. Trong trường hợp này, nơi anh ta thực hiện phương thức nguyên gốc, anh ta nên sử dụng CoTaskMemAlloc() thay vì new/mallow(). Sau đó, marshaler interop sẽ chăm sóc giải phóng bộ nhớ. –