我是从C#调用以下VC++方法C#互操作释放存储器在非托管代码
__declspec(dllexport) unsigned char* Get_Version_String()
如下分配:
internal static class NativeMethods
{
[DllImport("my.dll"),
CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true,
CallingConvention = CallingConvention.Cdecl)]
internal static extern string Get_Version_String();
}
上面的代码是在其中面向.NET库3.5。当我从3.5程序集中调用它时,它工作正常;从4.5组装时调用它,但是,它会导致
0xC0000374:堆已损坏
阅读this question后,我改变了我的方法调用如下:
[DllImport("my.dll",
EntryPoint = "Get_Version_String",
CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true,
CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr Get_Version_String_PInvoke();
internal static string Get_Version_String()
{
IntPtr ptr = Get_Version_String_PInvoke();
string versionString = Marshal.PtrToStringAnsi(ptr);
return versionString;
}
这个按预期工作,但Hans Passant的答案带有警告:
您找到的解决方法是正确的,编组不会尝试释放内存
IntPtr
。请注意,如果C代码返回一个不需要释放的const char*
,这实际上只会实现良好的结果。如果情况并非如此,你会有永久的内存泄漏。
由于C++方法不返回const
,我假设我的特定函数的解决方法将导致内存泄漏。
我无法更改原始方法,所以我找到了this other question,它讨论了如何从管理代码中释放内存。但是,调用要么Marshal.FreeHGlobal(ptr)
或Marshal.FreeCoTaskMem(ptr)
也扔0xC0000374: A heap has been corrupted.
谁能
一)证实这种方法确实会从内存泄漏受苦,
B)如果是这样,建议如何从指针释放内存在托管代码?
的C++方法主体,简化的,具体如下:预先
unsigned char versionString[50];
__declspec(dllexport) unsigned char* Get_Version_String()
{
strcpy((char *) versionString, "Key1:[xx],Key2:[xx],Key3:[xx],Key4:[xx]");
// string manipulation
return versionString;
}
谢谢,对不起,如果这是微不足道;我既不是C++也不是Interop专家。
我可能会尽可能激发内存泄漏。如果这个非托管代码可以被多次执行而没有不必要的影响,那么可以偶尔使用'GC.Collect()'调用将其打包到无限循环中,并观察内存消耗。 – Edin
好的,我可以测试一下。我应该如何“偶尔”调用GC.Collect()?每一分钟?更长? – user5877732
GC.Collect()不一定需要。如果您正在运行32位应用程序,则内存将大约为2Gb。但是,这是一种很好的方式来查看内存是否被更早释放,而不仅仅是等待OutOfMemoryException。多久调用一次取决于记忆分配的速度。如果这是缓慢的,那么每分钟就足够了。但是,如果速度非常快,您可以每隔一秒左右调用一次。另请注意,每次调用GC.Collect()都不一定会导致垃圾回收。并且不要在生产性代码中调用GC.Collect() - 在大多数情况下不需要。 – Edin