如何在 C# 中释放在 C++ 中分配的内存
Posted
技术标签:
【中文标题】如何在 C# 中释放在 C++ 中分配的内存【英文标题】:How to free memory in C# that is allocated in C++ 【发布时间】:2015-05-26 16:47:00 【问题描述】:我有一个 C++ dll,它正在从相机读取视频帧。这些帧在通过指向调用者(C# 程序)的指针返回的 DLL 中分配。
当 C# 处理完特定的视频帧后,它需要清理它。 DLL 接口和内存管理被包装在 C# 中的一次性类中,因此更易于控制。但是,似乎内存没有被释放/释放。我的进程的内存占用越来越大,不到一分钟,我在 C++ DLL 中出现分配错误,因为没有任何内存可用。
每个视频帧略大于 9 MB。代码很多,我就简单提供一下分配/解除分配/类型/等。
首先:在 C++ 中为相机字节分配原始缓冲区。
dst = new unsigned char[mFrameLengthInBytes];
第二:从原始指针转移回 DLL 边界作为 unsigned char * 并进入 C# 中的 IntPtr
IntPtr pFrame = VideoSource_GetFrame(mCamera, ImageFormat.BAYER);
return new VideoFrame(pFrame, .... );
所以现在 IntPtr 被传递到 VideoFrame 类的 CTOR 中。在 CTOR 内部,IntPtr 被复制到类的内部成员,如下所示:
IntPtr dataPtr;
public VideoFrame(IntPtr pDataToCopy, ...)
...
this.dataPtr = pDataToCopy;
我的理解是这是一个浅拷贝,该类现在引用原始数据缓冲区。框架被使用/处理/等。稍后,VideoFrame类被释放,下面用于清理内存。
Marshal.FreeHGlobal(this.dataPtr);
我怀疑问题是...... dataPtr 是一个 IntPtr 并且 C# 无法知道底层缓冲区实际上是 9 MB,对吗?有没有办法告诉它此时要释放多少内存?我是否使用了错误的 C# 免费方法?有专门针对这种情况的吗?
【问题讨论】:
VideoSource_ReleaseFrame(pFrame) ? 如果内存是在 C++ dll 中分配的,那么它也应该在那里被释放。 API 没有那种调用。它全部重用代码,最初是为在其他 C++ 程序中使用而开发的,因此您可以执行 delete [] 并摆脱内存。我无法更改界面,但我可以更改代码。如果在 c# 中没有办法,我将不得不在 c++ 中做一个解决方法。 @LawfulEvilThe API doesn't have that sort of call
这是一个巨大的差距。内存分配方式有很多种,每种方式都有自己匹配的释放函数。此外,除非您想解决更多问题,否则 DLL 应该重新分配内存,因为它知道它是如何分配内存的,而且 DLL 正在同一个堆上工作,而不是 C# 模块所在的(可能)不同的堆。使用。
告诉我。老板是关于重用的,他说我可以抓住这个,不用预算任何新的开发时间,因为它都是开箱即用的。感谢您的帮助。
【参考方案1】:
您需要在您正在使用的库中调用相应的“免费”方法。
通过new
分配的内存是C++ 运行时的一部分,调用FreeHGlobal
将不起作用。您需要针对内存调用(一种或另一种方式)delete[]
。
如果这是您自己的库,则创建一个删除内存的函数(例如VideoSource_FreeFrame
)。例如:
void VideoSource_FreeFrame(unsigned char *buffer)
delete[] buffer;
然后从 C# 调用它,传入你返回的 IntPtr
。
【讨论】:
我不熟悉 C++ 中委托的使用,但是否可以将分配和解除分配包装在一个函数中,并使用 C# 的回调委托来处理它之前的数据被释放?如果它能够只是一个电话,那将更加方便消费者。【参考方案2】:您需要(在 C++ 中)delete dst;
。这意味着您需要提供一个 C# 代码可以调用的 API,例如 FreeFrame(...)
,它正是这样做的。
【讨论】:
就我而言,它的删除 [],但是是的,看来我需要从其他利益相关者那里获得支持并更新 API 等。【参考方案3】:我同意第一个答案。不要在 C# 代码中释放它,使用任何神奇的礼仪咒语。用 C++ 编写一个释放内存的方法,然后从 C# 代码中调用它。不要养成在一个堆(本机)中分配内存并释放另一个堆(托管)的习惯,这只是个坏消息。
记住有效C++书中的一条规则:在构造函数中分配内存,在析构函数中释放内存。如果你不能在析构函数中做到这一点,那么在类内方法中做到这一点,而不是一些全局(或更糟糕的)友元函数。
【讨论】:
以上是关于如何在 C# 中释放在 C++ 中分配的内存的主要内容,如果未能解决你的问题,请参考以下文章