【发布时间】:2013-07-16 03:39:05
【问题描述】:
这行得通:
[DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetError")]
private static extern IntPtr SDL_GetError();
public static string GetError()
{
return Marshal.PtrToStringAnsi(SDL_GetError());
}
这会崩溃:
[DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetError")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetError();
This article 暗示 return 属性本质上就像调用Marshal.PtrToStringAnsi,那么有什么关系呢?
正如 Daniel pointed out,它可能崩溃了,因为编组器正在尝试释放内存。文章还指出,
注意:请注意,非托管端不得使用“new”关键字或“malloc()”C 函数来分配内存。在这些情况下,Interop Marshaler 将无法释放内存。这是因为“new”关键字依赖于编译器,而“malloc”函数依赖于 C 库。
我尝试使用Marshal.FreeHGlobal、Marshal.FreeCoTaskMem 和Marshal.FreeBSTR 释放char 指针——它们都崩溃了。没有任何其他方法可以释放内存AFAIK,所以我猜内存是通过new 或malloc() 分配的。那现在怎么办,我被圈套了?我的程序中存在永久性内存泄漏?
我检查了来源。该字符串是通过static char errmsg[SDL_ERRBUFIZE] 创建的。我的 C 生锈了,但我猜它被声明为static,这样当它超出函数范围时就不会被释放。我不记得静态数组在内存中的位置;有什么办法可以释放它们吗?
编辑:等等……它是静态的。这意味着每次出现新错误时,它都会覆盖旧的错误消息,因此SDL_GetError() 只返回最新的错误消息。因此,我不必担心释放它。
因此,如果所有return: MarshalAs... 选项都试图释放内存,那么唯一的解决方案就是我目前的解决方案。毕竟这是最优的。
【问题讨论】:
-
是的,如果是静态的,那么内存一定不能被释放。所以唯一的方法是手动编组,否则 CLR 编组器将释放内存。
标签: c# c marshalling