Marshal.StructureToPtr出现无法解释的内存泄漏
Unexplained memory leak with Marshal.StructureToPtr
我正在开发一个应用程序,该应用程序通过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引用的本机结构被整理并复制到"数据"管理结构
管理结构被复制回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;
}
您的结构中有指向字符串的指针。这些指针是在非托管代码中分配的(使用new wchar_t[<a number>]
),对吗?当封送处理指向托管代码的指针时,封送处理程序会创建托管字符串,并用非托管字符数组的内容填充它们。当将它们封送回非托管代码时,封送拆收器会复制整个结构内容,包括字符指针,并为它们分配新值(使用CoTaskMemAlloc()
为每个字符串分配内存)。这就是Marshal.StructureToPtr
的第三个参数的作用。如果设置为true,封送拆收器将尝试解除分配由字符指针指向的内存(使用CoTaskMemFree()
)。如果使用new
运算符为字符指针分配了内存,则无法将该参数设置为true,并且通过封送回非托管状态,将丢失指向已分配内存的指针(封送器用新值覆盖它们)。由于您没有释放封送拆收器分配的内存,因此最终会出现内存泄漏。
处理这种情况的最佳选择是:
将字符串封送为指针,并使用Marshal.PtrToStringUni()
将其转换为字符串:
[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;
public IntPtr ParamTwelve; // <-- These are your strings
public IntPtr ParamThirteen; // <--
public IntPtr ParamFourteen; // <--
public IntPtr ParamFifteen;
public IntPtr ParamSixteen;
}
以及编组:
MyObject data = (MyObject)Marshal.PtrToStructure(ptr, typeof(MyObject));
var str1 = Marshal.PtrToStringUni(data.ParamTwelve);
var str2 = Marshal.PtrToStringUni(data.ParamThirteen);
var str3 = Marshal.PtrToStringUni(data.ParamFourteen);
Marshal.StructureToPtr(data, ptr, false);
- 从构造函数抛出异常时如何克服内存泄漏
- malloc() 可能出现内存泄漏
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 尽管遵循了规则,内存泄漏在哪里
- 为什么调用堆栈数组会导致内存泄漏
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 使用模板类的自定义列表类型中的内存泄漏
- 为什么以下C++代码中存在内存泄漏?
- OpenCV 我应该使用智能指针来防止内存泄漏吗?
- 我是否生成线程并导致内存泄漏?
- 多线程程序中出现意外的内存泄漏
- 为什么此函数会导致内存泄漏?
- 在 C++ 库中使用cythonized python时内存泄漏
- 需要帮助查找内存泄漏
- 瓦尔格林德的内存泄漏使用新的
- 无法找出我的代码中的内存泄漏
- C++ 结构内部的unordered_map会导致内存泄漏问题吗?
- 可视化 使用 VS Code 查找C++应用程序中的内存泄漏
- Shared_ptr双链接列表内存泄漏
- C++ 在类中使用常量引用文本时 O2 内存泄漏