C#清理C ++分配的内存吗?

时间:2009-03-26 14:01:54

标签: c# c++ com interop

我有一个带有以下签名的假设COM对象

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

使用new / malloc在C ++中分配内存。一旦这是在C#中,使用RCW,我如何确保正确释放内存?我认为.NET很难释放,考虑到在C ++中你需要知道它是否已经分配了new / malloc / mm_malloc才能正确释放它。那么,清理我的C ++分配数组的合适方法是什么?感谢。

4 个答案:

答案 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的内容一致。