我是否需要删除通过非托管代码中的 Marshal.PtrToStructure 封送的结构?
-
20-08-2019 - |
题
我有这个 C++ 代码:
extern "C" __declspec(dllexport) VOID AllocateFoo(MY_DATA_STRUCTURE** foo)
{
*foo = new MY_DATA_STRUCTURE;
//do stuff to foo
}
然后在 C# 中我这样调用该函数:
[DllImport("MyDll.dll")]
static extern void AllocateFoo(out IntPtr pMyDataStruct);
...
MyDataStructure GetMyDataStructure()
{
IntPtr pData;
ManagedAllocateFooDelegate(out pData);
MyDataStructure foo = (MyDataStructure)Marshal.PtrToStructure(pData, typeof(MyDataStructure));
return foo;
}
其中 MyDataStructure 是一个与 MY_DATA_STRUCTURE 相对应的结构(而不是类),并且成员被适当地编组。
所以问题:当 MyDataStructure 被 GC 时,我是否需要存储 pData,然后在非托管代码中再次释放它?MSDN 对于 Marshal.PtrToStructure(IntPtr, Type) 的说法是:“元帅数据从不受管理的内存块到指定类型的新分配的托管对象。”在那句话中,“马歇尔”的意思是“复制”吗?在这种情况下,我需要保留 (IntPtr pData) 然后将其传递给非托管代码(在 MyDataStructure 析构函数中),以便我可以执行 C++“删除”?
我已经搜索过,但找不到足够明确的答案。
解决方案
由于埃里克说,元帅确实意味着副本,但我不认为他回答你的问题的要点。
您是否需要守住的pData本地指针,直到MyDataStructure是GCed?否。
在编组,你的MyDataStructure例如,FOO,包含结构的副本由pData所指向。你不必守住的pData任何更长的时间。为了避免内存泄漏,必须传递的pData到另一个非托管函数,将其删除,并可以封送处理后立即进行,无论你持有到MyDataStructure实例有多长。
其他提示
是的,在这种情况下,Marshall 的意思是复制;因此,您需要在非托管代码中释放内存。对 PtrToStructure 的所有调用都是从 pData 指向的内存位置读取由目标结构“MyDataStructure”的大小指示的字节数。
当然,详细信息取决于“MyDataStructure”的具体外观(您是否在 MyDataStructure 中使用任何 FieldOffset 或 StructLayout 属性) - 但最终结果是 PtrToStructure 返回的是数据的副本。
作为 格贝根 指出在 他的回答, ,我没有回答你问题的要点。是的,您需要在非托管代码中删除结构的非托管副本,但是不需要,您不需要保留 pData - 您可以在对 PtrToStructure 的调用完成后立即删除非托管副本。
附:我编辑了我的帖子以包含此信息,以便将答案合并到一篇帖子中 - 如果有人赞成这个答案,请也赞成 GBegen 的答案,以表彰他的贡献。