如何在c#中释放c++中分配的内存

How to free memory in C# that is allocated in C++

本文关键字:分配 内存 c++ 释放      更新时间:2023-10-16

我有一个c++ dll,它正在从相机读取视频帧。这些帧在DLL中被分配,DLL通过指向调用者(c#程序)的指针返回。

当c#处理完一个特定的视频帧时,它需要清理它。在c#中,DLL接口和内存管理被封装在一个一次性类中,因此更容易控制。然而,似乎内存没有被释放。我的进程的内存占用越来越大,在不到一分钟的时间里,我在c++ DLL中得到分配错误,因为没有任何内存剩余。

视频帧每帧超过9mb。有很多代码,所以我只提供分配/释放/类型等。

First:在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# free方法?有专门针对这种情况的吗?

您需要调用您正在使用的库中相应的"free"方法。

通过new分配的内存是c++运行时的一部分,调用FreeHGlobal将不起作用。您需要调用(一种或另一种方式)delete[]对内存。

如果这是您自己的库,那么创建一个删除内存的函数(例如VideoSource_FreeFrame)。如:

void VideoSource_FreeFrame(unsigned char *buffer)
{
  delete[] buffer;
}

然后从c#调用它,传入你得到的IntPtr

您需要(在c++中)delete dst;。这意味着你需要提供一个c#代码可以调用的API,比如FreeFrame(...),它就是这样做的。

我同意第一个答案。不要在c#代码中释放它,使用任何神奇的、仪式性的咒语。用c++写一个释放内存的方法,然后在c#代码中调用它。不要养成在一个堆(本机)分配内存并释放另一个堆(托管)的习惯,这只是坏消息。

记住书中有效的c++规则之一:在构造函数中分配内存,在析构函数中释放内存。如果不能在析构函数中完成,那么就在类内方法中完成,而不是在某个全局(甚至更糟)友元函数中完成。