簡體   English   中英

關於是否使用不安全代碼和stackalloc固定的困惑

[英]Confusion on whether to use fixed with unsafe code and stackalloc

我在下面有一段代碼,只有一行注釋掉了。 CreateArray方法中發生的事情與注釋掉的行相同。 我的問題是為什么當b->ArrayItems = d被取消注釋時它會起作用,但是當注釋掉時返回垃圾? 我不認為我必須“修復”任何東西,因為所有信息都是不受管理的。 這個假設是不正確的?

class Program
{
    unsafe static void Main(string[] args)
    {
        someInstance* b = stackalloc someInstance[1];
        someInstance* d = stackalloc someInstance[8];

        b->CreateArray();
//      b->ArrayItems = d;

        *(b->ArrayItems)++ = new someInstance() { IntConstant = 5 };
        *(b->ArrayItems)++ = new someInstance() { IntConstant = 6 }; 

        Console.WriteLine((b)->ArrayItems->IntConstant);
        Console.WriteLine(((b)->ArrayItems - 1)->IntConstant);
        Console.WriteLine(((b)->ArrayItems - 2)->IntConstant);
        Console.Read();
    }
}

public unsafe struct someInstance
{
    public someInstance* ArrayItems;
    public int IntConstant;
    public void CreateArray()
    {
        someInstance* d = stackalloc someInstance[8];
        ArrayItems = d;
    }
}

我的問題是為什么當行被取消注釋時它會起作用,但在注釋掉時返回垃圾。

注釋行是掩蓋 CreateArray引起的錯誤的原因。 評論它暴露了這個bug。 但無論如何,這個bug都存在。

正如規范明確指出:

在該函數成員返回時,將自動丟棄在執行函數成員期間創建的所有堆棧分配的內存塊。

CreateArray函數分配一個塊,存儲指向塊的指針,塊被丟棄,現在你有一個指向垃圾塊的指針。 必須 永遠不會存儲指向stackalloc'd塊的指針,以便在塊變為無效后可以訪問存儲。 如果您需要存儲對它的引用,Heap會分配塊,並且在完成后記得取消分配它。

請記住,在不安全的代碼中, 您需要完全了解托管內存模型的所有內容。 一切 如果您不了解托管內存的所有內容,請不要編寫不安全的代碼。

那就是說,讓我們解決一下你似乎更大的困惑,那就是“什么時候需要修復內存來獲取指針?” 答案很簡單。 當且僅當它是可移動內存時,您必須修復內存。 修復將可移動存儲器轉換為不可移動的存儲器; 這就是修復的目的

你只能拿一些不可移動的東西; 如果你取一個可移動的東西的地址然后移動那么顯然地址是錯誤的。 您需要確保在獲取其地址之前內存不會移動,並且您需要確保在再次移動后不再使用該地址。

Stackalloc在callstack上分配一些空間,當你向上移出當前的上下文級別時(例如,留下一個方法),該空間就會丟失。 你的問題是當stackalloc在一個方法中時,當你離開那個方法時,堆棧的那個區域就不再是你的了。

所以,如果你這樣做:

foo()
{
    stuff = stackalloc byte[1]
    Do something with stuff
}

“stuff”只在foo中有效,一旦你離開foo,堆棧就會被收回,這意味着如果你這樣做:

foo()
{
    byte* allocate()
    {
        return stackalloc[1]
    }

    stuff = allocate()
    do something with stuff
}

當你離開allocate方法時,allocate的返回值變成垃圾,這意味着“東西”從來沒有任何意義。

您的假設部分正確,但錯誤理解。 以下是此MSDN頁面的引用:

在不安全模式下,您可以在堆棧上分配內存,它不受垃圾回收的影響,因此不需要固定。 有關更多信息,請參閱stackalloc

有些語句會自動在堆棧上分配變量(即方法中的值類型),其他stackalloc需要使用stackalloc專門指定。

在方法結束后丟棄堆棧分配的內存,因此您的問題(請參閱Eric Lipperts回答,誰在我之前寫了這個)。

暫無
暫無

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

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