【发布时间】:2012-11-21 01:11:30
【问题描述】:
我正在开发一个应用程序,该应用程序通过 C++/CLR 包装器涉及本机 C++ 到 C# 互操作。
我在执行以下操作时遇到问题,导致内存泄漏:
MyObject data = (MyObject)Marshal.PtrToStructure(ptr, typeof(MyObject));
Marshal.StructureToPtr(data, ptr, false);
(注意:我意识到此时我实际上并没有对“数据”做任何事情,所以这是多余的。)
内存使用量持续上升,直到应用程序因系统内存不足而崩溃。当我删除此代码时,这不会发生。它不是垃圾收集器,因为 a)它应该在系统内存不足时收集,b)我尝试使用 GC.Collect() 强制它。
事实上,我已将泄漏范围缩小到 StructureToPtr 命令。
我无法将第三个参数设置为“true”,因为内存是由本机 C++ 分配的,而 C# 认为这个“受保护”的内存无法释放。
我检查了填充的 Data 结构是否完好无损,具有有效数据,并且与等效的原生结构大小相同。
在我看来,这就是应该发生的事情:
我的 ptr 引用的本机结构被编组并复制到“数据”托管结构中
manage 结构被复制回 ptr 引用的同一内存中。
我看不出这是如何导致内存泄漏的,因为它的结构大小完全相同,被复制回相同的内存空间。但显然确实如此,删除代码会堵塞泄漏。
这里有一些我没有正确理解的机制吗?
编辑:根据要求,这里是“MyObject”的声明。
C#:
[StructLayout(LayoutKind.Sequential)]
public struct MyObject
{
[MarshalAs(UnmanagedType.I1)]
public bool ParamOne;
[MarshalAs(UnmanagedType.I1)]
public bool ParamTwo;
[MarshalAs(UnmanagedType.I1)]
public bool ParamThree;
[MarshalAs(UnmanagedType.I1)]
public bool ParamFour;
[MarshalAs(UnmanagedType.I1)]
public bool ParamFive;
[MarshalAs(UnmanagedType.I1)]
public bool ParamSix;
[MarshalAs(UnmanagedType.R4)]
public float ParamSeven;
[MarshalAs(UnmanagedType.R4)]
public float ParamEight;
[MarshalAs(UnmanagedType.R4)]
public float ParamNine;
public Vector2f ParamTen;
public Vector2f ParamEleven;
[MarshalAs(UnmanagedType.LPWStr)]
public string ParamTwelve;
[MarshalAs(UnmanagedType.LPWStr)]
public string ParamThirteen;
[MarshalAs(UnmanagedType.LPWStr)]
public string ParamFourteen;
public IntPtr ParamFifteen;
public IntPtr ParamSixteen;
}
C++:
struct MyObject
{
public:
bool ParamOne;
bool ParamTwo;
bool ParamThree;
bool ParamFour;
bool ParamFive;
bool ParamSix;
float ParamSeven;
float ParamEight;
float ParamNine;
Vector2f ParamTen;
Vector2f ParamEleven;
wchar_t * ParamTwelve;
wchar_t * ParamThirteen;
wchar_t * ParamFourteen;
void * ParamFifteen;
void * ParamSixteen;
};
Vector2f的定义如下:
[StructLayout(LayoutKind.Sequential)]
public struct Vector2f
{
[MarshalAs(UnmanagedType.R4)]
float x;
[MarshalAs(UnmanagedType.R4)]
float y;
}
【问题讨论】:
-
可以发一下
MyObject的定义吗? -
"MyObject" 听起来不像是一个结构。您确实需要记录下来才能得到一个好的答案。
-
您的内存泄漏情况如何?您是如何发现泄漏的?
-
内存使用量持续上升,直到应用程序因系统内存不足而崩溃。当我删除此代码时,这不会发生。它不是垃圾收集器,因为 a)它应该在系统内存不足时收集,b)我尝试使用 GC.Collect() 强制它。
-
结构中的 wchar_t* 和 void* 指针是不可避免的泄漏。它们需要被销毁,除非本机代码使用 CoTaskMemAlloc(),否则不能在托管代码中这样做。当然不是。这种代码很难在纯原生代码中可靠地进行互操作,在 C# 中尝试它并没有变得更好。
标签: c# c++ memory interop marshalling