我是從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