簡體   English   中英

在托管.NET代碼中分配非托管內存

[英]Allocating unmanaged memory in managed .NET code

嗨,我有一個非托管函數,該函數占用malloc分配的大量內存,並在以后以異步方式對其進行釋放。 我想將其包裝到托管包裝器中。 下列代碼可以嗎?

void managed_fx (byte data __gc[], size_t size)
{
    //  Pin the data
    byte __pin *pinned_data = &data [0];

    //  Copy data to the unmanaged buffer.
    void *unmanaged_data = malloc (size);
    memcpy (unmanaged_data, (byte*) pinned_data, size);

    //  Forward the call
    fx (unmanaged_data, size);
}

我的MC ++有點生銹,但是我認為__pin固定源變量,直到“ pinned_data”超出范圍為止(至少,這是C ++ / CLI中等效的pin_ptr所做的事情)。 通常,您應該盡快取消固定該引腳,即出於性能原因,不應在同一范圍內調用fx。

在這種情況下,是否需要固定?

是。 您要從非托管代碼訪問托管內存。

gc可以在memcpy之前取消分配它嗎

不會。數據有很強的參考性,因此gc不會收集數據。 但是,它可能會收集其他一些對象,並在壓縮步驟中將數據移動到內存中。 然后,malloc將訪問錯誤的內存區域。 固定會防止這種情況,但會增加GC簿記的費用(這就是為什么您應盡快取消固定對象的原因)。

即使在托管代碼中使用了malloc,它也會分配非托管內存嗎?

是。

您需要測試您的malloc,它實際上已經分配了您的指針。 不了解C ++ / CLI,所以我不知道您的管腳是否可以工作。 您是否不需要使用編組庫來確保在復制內存時將其固定?

閱讀此內容以獲取有關如何分配非托管數據的信息。 看一下馬歇爾課。 也許會有一些方法可以代替您的managed_fx函數。

你是

  1. 假設數據數組的大小至少相同。 這是一個可能等待發生的錯誤

  2. 不檢查malloc()的結果

  3. 無論如何,您可能都不需要這樣做,只需傳遞固定的字節指針就可以了(除非被調用的fx()函數以某種方式更改了數據,在這種情況下可能需要復制)。 基於稍后釋放內存,這很有可能不會發生。

考慮到這一點,這里是一個固定的版本

void managed_fx (byte data __gc[], size_t size)
{
    if (data.Length < size)
        throw gcnew System.IndexOutOfRangeException(
            "the unmanaged buffer is not big enough");
    //  Pin the data
    byte __pin *pinned_data = &data [0];

    //  Copy data to the unmanaged buffer.
    void *unmanaged_data = malloc (size);
    if (unmanaged_data == NULL) 
        throw gcnew OutOfMemoryException(
            "could not allocate memory for the unmanaged buffer");
    memcpy (unmanaged_data, (byte*) pinned_data, size);

    //  Forward the call
    fx (unamanged_data, size);
}

要回答其他問題:

固定是執行memcpy所必需的。 它不能防止GC運行時刪除內存(從技術上講確實可以,但是只是保留對其的引用也是如此),可以防止它在內存中移動 由於memcpy是非托管函數-它無法處理正在處理的指針在內存中的移動。 malloc完全不受托管(盡管運行時庫可以自由使用托管堆的保留區來執行此操作)。

在源C ++ / CLI中,關於“代碼”是托管還是非托管沒有明顯區別。 在編譯時,某些部分將是CIL中間代碼,其他部分將是純本地代碼,重要的是使用的變量是托管的還是非托管的。 托管引用(帶有^的任何內容)只能由本身托管的代碼來操縱/使用。 這意味着如果運行時更改了托管對象在內存中的位置,則可以隨意更改所使用的基礎指針的值。 它以一種對托管功能安全的方式來執行此操作(在功能發生變化時它們會暫停)。 由於存在許多有用的功能,卻不知道如何處理此類托管引用,因此您可能最終需要使用指向它們的簡單指針。 由於此操作是不安全的(如果GC在引用中進行了移動),則存在固定指針以使此操作安全且簡單,因為它既需要使用指針,又會在該指針的生命周期內阻止運行時將指針移至變量。

好吧,讓我們變得更簡單:

void managed_fx (byte data __gc[])
{
     //  Pin the data
     byte __pin *pinned_data = &data [0];

     //  Copy data to the unmanaged buffer.
     void *unmanaged_data = malloc (data.Length);
     assert (unmanaged_data);
     memcpy (unmanaged_data, (byte*) pinned_data, data.Length);

     //  Forward the call
     fx (unamanged_data, data.Length);
 }

不過,我有幾個問題:

  1. 在這種情況下,是否需要固定? gc可以在memcpy發生之前取消分配它嗎?
  2. 即使在托管代碼中使用了malloc,它也會分配非托管內存嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM