我有一个带有以下签名的假设COM对象
void MemAlloc(ref double[] test, int membercount)
使用new / malloc在C ++中分配内存。一旦这是在C#中,使用RCW,我如何确保正确释放内存?我认为.NET很难释放,考虑到在C ++中你需要知道它是否已经分配了new / malloc / mm_malloc才能正确释放它。那么,清理我的C ++分配数组的合适方法是什么?感谢。
答案 0 :(得分:8)
我相信您应该将CoTaskMemAlloc()用于您希望从托管端明确释放的内存。一旦不再可用,CLR将负责释放内存。如果要明确释放它,可以使用托管的Marshal.CoTaskFree()例程。
一般来说,interop marshaler和CLR遵守COM约定来释放内存;收件人负责释放记忆。因此,如果将内存返回给托管调用者,CLR / Interop封送程序通常会处理释放本机调用中分配的内存。
来自Memory Management with the Interop Marshaler(msdn):
interop marshaler总是尝试 释放由非托管分配的内存 码。此行为符合COM 内存管理规则,但不同 来自管理本机C ++的规则。
如果您预料到,可能会出现混乱 本机C ++行为(没有内存 释放时使用平台调用, 这会自动释放内存 指针。例如,调用 遵循C ++中的非托管方法 DLL不会自动释放任何内容 记忆。
运行时始终使用 释放内存的CoTaskMemFree方法。 如果您正在使用的内存是 未分配CoTaskMemAlloc 方法,你必须使用IntPtr和 使用手动释放内存 适当的方法。
答案 1 :(得分:6)
将其包装在一个实现IDisposable的对象中,并确保C#包装器被处理掉。
Here's a blog I wrote关于实现IDisposable的简单方法。
答案 2 :(得分:1)
我几乎100%确定CLR不会自动释放分配用于测试的内存(如果它是PInvoke我会100%肯定)。原因是,CLR如何知道你用来分配内存的东西?即它没有。
编写此函数的更安全的方法如下
void MemAlloc(ref IntPtr arrayPtr, int membercount)
收到回电后,您可以执行以下操作。
var count = GetTheCount();
var arrayPtr = IntPtr.Zero;
obj.MemAlloc(ref arrayPtr, count);
byte[] test = MarshalThePtrToByteArray(arrayPtr, count);
Marshal.FreeCoTaskMem(arrayPtr);
这是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;
}
答案 3 :(得分:1)
这本书.NET 2.0 Interoperbility Recipes看起来很方便。这似乎与Arnshea关于CoTaskMemFree的内容一致。