C++ DLL分配内存是否会被C#回收?stb_image互操作疑问
关于Unity中C++ stb_image与.NET互操作的内存问题解答
问题1:.NET垃圾回收是否会提前释放C++分配的内存?
不会。IntPtr本质只是一个存储内存地址的数值类型,.NET的垃圾回收器(GC)完全不知道这块内存是在C++堆上分配的,所以它既不会主动释放这块内存,也不会移动或覆盖它的内容。只要你自己不调用释放函数,这块内存会一直保留在C++堆中,直到进程结束或者你显式释放,后续保存图像文件的操作不会被GC干扰。
问题2:能否通过C#传递IntPtr调用stbi_image_free来正确释放内存?
完全可以,只要在C++侧正确封装stbi_image_free函数即可。
补充完整的代码实现:
C++侧代码
#include "stb_image.h" __declspec(dllexport) unsigned char* GetImage(const char* filename, int* width, int* height, int* comp) { return stbi_load(filename, width, height, comp, 0); } __declspec(dllexport) void FreeImage(unsigned char* data) { stbi_image_free(data); }
C#侧DllImport封装
public static class ImageReader { [DllImport("YourCppDllName.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr GetImage(string filename, ref int width, ref int height, ref int comp); [DllImport("YourCppDllName.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void FreeImage(IntPtr data); public static TextureFormat FormatFromPixelComponents(int comp) { switch(comp) { case 3: return TextureFormat.RGB24; case 4: return TextureFormat.RGBA32; default: return TextureFormat.RGB24; } } }
C#侧使用示例(补充释放逻辑)
int width = 0, height = 0; int pixelComponents = 0; IntPtr ptr = ImageReader.GetImage(path, ref width, ref height, ref pixelComponents); if (ptr == IntPtr.Zero) throw new Exception("Error loading image"); try { Texture2D ex = new Texture2D(width, height, ImageReader.FormatFromPixelComponents(pixelComponents), false); ex.LoadRawTextureData(ptr, width * height * pixelComponents); ex.Apply(); // Sends texture to GPU // 执行保存图像文件的操作 byte[] imageBytes = ex.EncodeToPNG(); File.WriteAllBytes(Path.Combine(Application.persistentDataPath, "saved.png"), imageBytes); } finally { // 无论是否出错,都要释放内存避免泄漏 ImageReader.FreeImage(ptr); }
关键注意事项
- 必须确保传递给
FreeImage的IntPtr是GetImage返回的、由stbi_load分配的内存地址,传入其他指针会导致未定义行为(比如程序崩溃)。 - 用
try-finally块包裹内存使用逻辑,确保异常场景下也能释放内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Gwendolyn Krezel
相关产品推荐
相关产品推荐

