【问题标题】:Delete memory allocated in C# in C++ code在 C++ 代码中删除 C# 中分配的内存
【发布时间】:2020-01-25 02:36:05
【问题描述】:

我有 C#(核心)和 C++(非托管 DLL)之间的代码互操作。

在 C# 中使用 Marshal.AllocHGlobal() 分配的内存需要在 C# 中使用 Marshal.FreeHGlobal() 释放。

在 C++ 中使用 new 分配的内存需要在 C++ 中使用 delete 释放。

由于 GC 不再跟踪这些内存处理程序,我可以随时使用 deleteFreeHGlobal() 吗?

【问题讨论】:

  • 不,它们分别跟踪内存分配。一个不知道另一个。
  • 我刚刚发现,在 dotnet core 3.0 中,我实际上可以将 C# byte[] 直接传递给 C++,而无需使用 Marshal.AllocHGlobal()
  • @sk 这不是什么新鲜事,.NET 一直能够做到这一点。阅读 PInvoke 和封送处理的实际工作原理。

标签: c# c++ memory-management interop


【解决方案1】:

不,你不能只使用任何你想释放内存的方法。你必须使用分配器要求你使用的任何东西。只有分配给定内存块的内存管理器知道如何正确释放该内存块。

例如,Marshal.AllocHGlobal() 的文档指出:

此方法从 Kernel32.dll 公开 Win32 LocalAlloc 函数

当 AllocHGlobal 调用 LocalAlloc 时,它会传递一个 LMEM_FIXED 标志,这会导致分配的内存被锁定到位。此外,分配的内存不是零填充的。

LocalAlloc() 的文档指出:

要释放内存,请使用 LocalFree 函数。使用 GlobalFree 释放使用 LocalAlloc 分配的内存是不安全的。

Marshal.FreeHGlobal() 使用的是什么:

FreeHGlobal 公开 Kernel32.DLL 中的 LocalFree 函数,该函数释放所有字节,因此您不能再使用 hglobal 指向的内存。

因此,允许 C# 代码使用 Marshal.AllocHGlobal() 分配内存,然后 C++ 代码使用 LocalFree() 释放该内存。相反,C++ 代码使用LocalAlloc(LMEM_FIXED) 分配内存,然后C# 代码使用Marshal.FreeHGlobal() 释放该内存。

同样,Marshal 类也有一个Marshal.AllocCoTaskMem() 方法:

此方法公开 COM CoTaskMemAlloc 函数,称为 COM 任务内存分配器。

CoTaskMemAlloc() 分配的内存被CoTaskMemFree() 释放:

释放之前通过调用 CoTaskMemAlloc 或 CoTaskMemRealloc 函数分配的任务内存块。

Marshal.FreeCoTaskMem() 使用的是什么:

FreeCoTaskMem 公开了 COM CoTaskMemFree 函数,该函数会释放所有字节,这样您就不能再使用 ptr 参数指向的内存了。

因此,允许 C# 代码使用 Marshal.AllocCoTaskMem() 分配内存,然后 C++ 代码使用 CoTaskMemFree() 释放该内存。相反,C++ 代码使用CoTaskMemAlloc() 分配内存,然后C# 代码使用Marshal.FreeCoTaskMem() 释放该内存。

现在,话虽如此,C++ 用于其newdelete 运算符的内存管理器是实现定义的。不能保证(或可能)new 使用 LocalAlloc()CoTaskMemAlloc(),或者 delete 使用 LocalFree()CoTaskMemFree()

因此,对于 C# 来说,释放由 new 分配的任何内存是不合法的,对于 C++ 来说,释放由 C# 分配的任何内存是不合法的。

【讨论】:

  • 感谢您提供的详细信息,这非常有帮助。我知道 C++ new / delete 实际上会调用构造函数 / 析构函数,这反过来又会 new / delete 更多内存。我这里指的是基本内存指针。
  • @sk 它比这更复杂。即使使用基本数据类型,您仍然不能不匹配分配和解除分配。还有其他一些我没有描述的因素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-19
  • 1970-01-01
  • 1970-01-01
  • 2014-10-25
  • 1970-01-01
相关资源
最近更新 更多