2017-07-27 152 views
3

我正在處理一些C#和C++非託管代碼,並且在處理內存時存在兩個不明白的地方。如果有人能幫助我理解:使用C#和C++非託管時的內存分配/取消分配

  1. 如果一個變量在C#下動態分配(使用new),然後傳遞給C++非託管代碼。該變量內存是否需要在用戶的C++非託管代碼下手動釋放?

  2. 如果一個變量在C++非託管(使用new)的情況下動態分配,然後傳遞給C#,可以安全地說垃圾收集器會釋放該內存嗎?

回答

2

這真的很簡單!

  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

1

作爲一個經驗法則,無論component/object分配的內存應該釋放內存。每做new a delete由做new

這是理想的。如果由於諸如您的原因而沒有遵循C++程序可能會終止並且在分配內存的生命週期結束時不存在,則您的C#應該清理,反之亦然。

2
  1. 不,因爲對象在託管堆上分配GC將像往常一樣處理重新分配。問題是你必須告訴他不要從非託管代碼中釋放或更改對象的地址,因爲GC無法知道從非託管代碼中使用對象的時間。這可以通過釘住對象來完成。 查看this的問題。

  2. 不,因爲對象在C++非託管堆上分配GC不會觸及它。你必須使用delete自己釋放它。

編輯: 如果您需要在非託管代碼中,反之亦然託管代碼和釋放分配一個對象,這是很好的知道有這個目的,你可以通過從Marshal.AllocHGlobalMarshal.FreeHGlobal呼叫使用OS堆C#在C++中會有類似的調用。