我有一个C++动态链接库,它从摄像机读取视频帧。这些帧在通过指向调用方( C#程序)的指针返回的DLL中得到分配。
当C#使用特定的视频帧完成时,它需要清理它。DLL接口和内存管理封装在C#中的一次性类中,因此更易于控制。但是,内存似乎没有被释放/释放。我的进程的内存占用不断增长,在不到一分钟的时间内,我就会在C++ DLL中得到分配错误,因为没有任何内存了。
每个视频帧都超过9MB。代码很多,所以我将简单地提供分配/释放位置/类型/等等。
首先:在C++中为摄像机字节分配原始缓冲区。
dst = new unsigned char[mFrameLengthInBytes];
第二:将原始指针作为无符号字符*从原始指针返回到跨DLL边界,并在C#中转换为C#中的
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#无法知道底层缓冲区实际上是9MB,对吗?有没有办法告诉它在这一点上要释放多少内存?我是不是使用了错误的C#免费方法?有专门针对这种情况的吗?
发布于 2015-05-26 16:57:50
您需要在正在使用的库中调用相应的“空闲”方法。
通过new
分配的内存是C++运行时的一部分,调用FreeHGlobal
不能工作。您需要(以某种方式)针对内存调用delete[]
。
如果这是您自己的库,那么创建一个函数(例如VideoSource_FreeFrame
)来删除内存。例:
void VideoSource_FreeFrame(unsigned char *buffer)
{
delete[] buffer;
}
然后从C#调用它,传入返回的IntPtr
。
发布于 2015-05-26 16:58:19
您需要(在c++中) delete dst;
。这意味着您需要提供一个C#代码可以调用的API,比如FreeFrame(...)
,它就是这样做的。
发布于 2015-05-26 17:08:57
我同意第一个答案。不要在C#代码中释放它,使用任何神奇的、礼拜化的咒语。在C++中编写一个释放内存的方法,并从您的C#代码中调用它。不要养成在一个堆(本机)中分配内存和释放另一个堆(管理)的习惯,这只是个坏消息。
记住“有效C++”一书中的一条规则:在构造函数中分配内存,并在析构函数中释放。如果在析构函数中不能这样做,可以使用类内方法,而不是全局(甚至更糟)的朋友函数。
https://stackoverflow.com/questions/30464431
复制相似问题