跨C++与C#使用结构体指针时,是否需要手动释放指针?
问题解答
必须手动释放这个Vector2*指针,C#的垃圾回收机制完全无法处理C++堆上分配的内存,不释放会导致内存泄漏。
原因
C中用new分配的内存属于非托管的原生堆,而C#的GC仅负责托管堆(.NET运行时管理的内存)的回收,对非托管内存没有感知。每次调用GetCursorPos都会在C堆上分配8字节(两个float)的内存,不手动释放的话,这些内存会一直占用直到程序退出。
解决方法
方法一:导出释放函数,在C#中调用释放
在C++代码中新增一个用于释放Vector2的导出函数:
extern "C" __declspec(dllexport) void FreeVector2(Vector2* vec) { delete vec; }
修改C#的调用代码,用finally保证即使出现异常也能释放内存:
[DllImport("Internal.dll", CallingConvention = CallingConvention.Cdecl)] internal static extern unsafe Vector2* GetCursorPos(); [DllImport("Internal.dll", CallingConvention = CallingConvention.Cdecl)] internal static extern unsafe void FreeVector2(Vector2* vec); public static unsafe (float x, float y) GetMousePosition() { Vector2* pos = GetCursorPos(); try { return (pos->X, pos->Y); } finally { FreeVector2(pos); } }
方法二:避免动态分配,让C#传入缓冲区(推荐)
这种方式不需要在C中动态分配内存,直接让C#提供结构体实例的指针,C将结果写入其中,从根源上避免内存管理问题:
修改C++的导出函数:
extern "C" __declspec(dllexport) void GetCursorPos(Vector2* outPos) { double xpos, ypos; glfwGetCursorPos(Window, &xpos, &ypos); outPos->X = (float)xpos; outPos->Y = (float)ypos; }
C#端定义对应结构体并调用:
[StructLayout(LayoutKind.Sequential)] public struct Vector2 { public float X; public float Y; } [DllImport("Internal.dll", CallingConvention = CallingConvention.Cdecl)] internal static extern unsafe void GetCursorPos(Vector2* outPos); public static (float x, float y) GetMousePosition() { unsafe { Vector2 pos; GetCursorPos(&pos); return (pos.X, pos.Y); } }
内容的提问来源于stack exchange,提问作者bquack-l
相关产品推荐
相关产品推荐

