[英]PInvoke: Allocate memory in C++ and free it in C#
我们使用PInvoke在C#和C ++之间进行交互。
我有一个如下的互操作结构,另一边有相同的布局C ++结构。
[StructLayout(LayoutKind.Sequential)]
public struct MeshDataStruct : IDisposable
{
public MeshDataStruct(double[] vertices, int[] triangles , int[] surfaces)
{
_vertex_count = vertices.Length / 3;
_vertices = Marshal.AllocHGlobal(_vertex_count*3*sizeof (double));
Marshal.Copy(vertices, 0, _vertices, _vertex_count);
}
// .. extract data methods to double[] etc.
private IntPtr _vertices;
private int _vertex_count;
public void Dispose()
{
if (_vertices != IntPtr.Zero)
{
Marshal.FreeHGlobal(_vertices);
_vertices = IntPtr.Zero;
}
}
}
现在我想添加第二个ctor
public MeshDataStruct(bool filled_in_by_native_codee)
{
_vertex_count = 0;
_vertices = IntPtr.Zero;
}
然后用C ++编写一个允许C ++填充数据的方法。 这将允许我们使用相同的结构进行输入和输出数据......
但是,据我所知, AllocHGlobal
可以在C#和C ++ / Cli中使用,但不是纯C ++。
所以我的问题是:如何在C ++中分配内存,以便我可以通过调用Marshal.FreeHGlobal(...)
安全地在C#端释放它?
从文档 :
AllocHGlobal是Marshal类中的两种内存分配方法之一。 (Marshal.AllocCoTaskMem是另一个。)此方法从Kernel32.dll公开Win32 LocalAlloc函数。
当AllocHGlobal调用LocalAlloc时,它会传递一个LMEM_FIXED标志,这会导致分配的内存被锁定到位。 此外,分配的内存不是零填充。
因此,您可以从非托管代码调用LocalAlloc
来分配内存,并从托管代码调用Marshal.FreeHGlobal
来释放它。 同样, LocalFree
可以在非托管代码中使用,以释放分配给Marshal.AllocHGlobal
内存。
由于文档也暗示,您可以使用CoTaskMemAlloc/CoTaskMemFree
和Marshal.AllocCoTaskMem/FreeCoTaskMem
执行相同的Marshal.AllocCoTaskMem/FreeCoTaskMem
。
话虽如此,你这样做是为了让自己陷入困境。 将分配和释放保存在相同的模块中要清晰得多。 以这种方式混合匹配很可能会导致对谁负责释放内存产生很大的困惑。
传统上,这总是很糟糕,Microsoft CRT使用HeapCreate()创建了自己的堆,以便在C或C ++程序中为malloc / new调用提供服务。 无法在C#中释放这样的内存,你没有堆句柄。
然而,这已经改变,从VS2012附带的CRT开始(msvcr120.dll及更高版本)。 它现在使用默认进程堆,即GetProcessHeap()返回的进程堆。 也是Marshal.Alloc / FreeHGlobal()使用的那个。 因此,如果本机代码不使用调试分配器(crtdbg.h),那么您现在可以使用它。 小心扔掉那个调试选项。
pinvoke marshaller没有改变,也没有改变。 如果它必须释放内存,就像作为函数返回值返回的数组或字符串一样,那么它将调用CoTaskMemFree()。 你的问题不清楚哪些适用。 如果有疑问并且您可以在您的本机代码中进行选择,那么您可以使用CoTaskMemAlloc()与C#代码中的Marshal.FreeCoTaskMem()配对。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.