使用C#和C++非托管时的内存分配/取消分配

问题描述:

我正在处理一些C#和C++非托管代码,并且在处理内存时存在两个不明白的地方。如果有人能帮助我理解:使用C#和C++非托管时的内存分配/取消分配

  1. 如果一个变量在C#下动态分配(使用new),然后传递给C++非托管代码。该变量内存是否需要在用户的C++非托管代码下手动释放?

  2. 如果一个变量在C++非托管(使用new)的情况下动态分配,然后传递给C#,可以安全地说垃圾收集器会释放该内存吗?

这真的很简单!

  1. 取决于
  2. 取决于

嗯,我们对此深感抱歉。

  1. 典型条件下,C#将跟踪的内存,并摆脱它的任何时间后,它不再对C#侧使用。它没有跟踪C++端的引用的方法,所以interop中的一个常见错误是在非托管端使用(导致加载FUN)之前,内存被释放了。这仅适用于直接引用内存的情况,而不适用于其被复制的情况(典型情况是在非托管调用期间锁定的byte[])。当传递给非托管代码的对象/指针的生命周期应该比被调用方法的运行时间长时,请勿使用自动编组。
  2. 在典型情况下,C#无法跟踪C++代码中的内存分配,因此您不能依赖自动内存管理。有例外(例如,某些COM方案),但几乎总是需要手动管理内存。这通常意味着将指针返回给C++代码来执行释放,除非它使用某种全局分配器(例如CoMemoryInitialize)。请记住,在非托管的世界中,没有一个内存管理器可以安全地调用来处理内存;无论如何,你真的没有必要的信息。

这当然只适用于指针。传递整数是非常好的,使用自动编组通常意味着编组负责处理大部分细节(虽然仍然只在最简单的情况下,所以要小心)。非托管代码是非托管 - 您需要完全理解内存如何分配以及如何,何时以及由谁负责清理内存。

+0

>互操作中的常见错误是内存在非托管侧完成之前解除分配。 请参阅https://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx – Wollmich

作为一个经验法则,无论component/object分配的内存应该释放内存。每做new a delete由做new

这是理想的。如果由于诸如您的原因而没有遵循C++程序可能会终止并且在分配内存的生命周期结束时不存在,则您的C#应该清理,反之亦然。

  1. 不,因为对象在托管堆上分配GC将像往常一样处理重新分配。问题是你必须告诉他不要从非托管代码中释放或更改对象的地址,因为GC无法知道从非托管代码中使用对象的时间。这可以通过钉住对象来完成。 查看this的问题。

  2. 不,因为对象在C++非托管堆上分配GC不会触及它。你必须使用delete自己释放它。

编辑: 如果您需要在非托管代码中,反之亦然托管代码和释放分配一个对象,这是很好的知道有这个目的,你可以通过从Marshal.AllocHGlobalMarshal.FreeHGlobal呼叫使用OS堆C#在C++中会有类似的调用。