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

问题描述 投票:0回答:4

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

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

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

c# c++ com interop
4个回答
9
投票

我相信您应该使用 CoTaskMemAlloc() 来存储您想要从托管端显式释放的内存。一旦内存不再可访问,CLR 将负责释放内存。如果您想显式释放它,您可以使用托管的 Marshal.CoTaskFree() 例程。

一般来说,互操作封送拆收器和 CLR 遵守释放内存的 COM 约定;接收者负责释放内存。因此,如果内存返回给托管调用者,CLR/Interop 封送拆收器通常会负责释放在本机调用中分配的内存。

来自 使用互操作封送拆收器进行内存管理 (msdn):

互操作封送拆收器始终尝试 释放非托管分配的内存 代码。此行为符合 COM 内存管理规则,但有所不同 来自管理本机 C++ 的规则。

如果您预期,可能会出现混乱 本机 C++ 行为(无内存 释放)使用平台调用时, 它会自动释放内存 指针。例如,调用 遵循 C++ 中的非托管方法 DLL 不会自动释放任何 记忆。

运行时总是使用 CoTaskMemFree 方法释放内存。 如果您正在使用的内存是 未使用 CoTaskMemAlloc 分配 方法,您必须使用 IntPtr 和 使用手动释放内存 适当的方法。


6
投票

将其包装在实现 IDisposable 的对象中,并确保 C# 包装器已被释放。

这是我写的博客,介绍了实现 IDisposable 的简单方法。


1
投票

这本书 .NET 2.0 Interoperbility Recipes 看起来很方便。看来很同意 Arnshea 所说的关于 CoTaskMemFree 的说法。


1
投票

我几乎 100% 确定 CLR 不会自动释放为测试分配的内存(如果是 P/Invoke,我将 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;
}
© www.soinside.com 2019 - 2024. All rights reserved.