[英]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.