如何在 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++ 中做一个解决方法。 @LawfulEvil The 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++ 中分配的内存的主要内容,如果未能解决你的问题,请参考以下文章

如何释放在我的 RPC 服务器中分配的内存?

在 C++ 中清除堆栈中分配的内存

释放在不同 DLL 中分配的内存

.NET 如何测量请求中分配的字节数?

JAVA里String数组在内存分配中分配的空间每个占几个字节?

如何找出 Linux 上的 GNU C++ 中剩余的可用内存量