簡體   English   中英

Stackalloc 與 C# 中固定大小的緩沖區。 有什么不同

[英]Stackalloc vs. Fixed sized buffer in C#. What is the difference

就我而言,以下代碼將在堆棧上創建一個數組:

unsafe struct Foo 
{ 
   public fixed int bar[10]; 
}
var foo = new Foo();

stackalloc 語句會做同樣的事情:

public void unsafe foo(int length)
{
    Span<int> bar = stackalloc int[length];
}

所以我想知道這些方法之間有什么區別。 還有固定大小緩沖區的目的是什么? 每個人都在談論性能提升,但我不明白為什么我需要它們,因為我已經可以使用 stackalloc 在堆棧上創建一個數組。 MSDN 說固定大小的緩沖區用於與其他平台“互操作”。 那么這個“互操作”是什么樣子的呢?

fixed語句僅說明數組已內聯(固定在結構體內部)。 這意味着存儲在數組中的數據直接存儲在您的結構中。 在您的示例中, Foo結構將具有存儲 10 個整數值所需的大小。 由於結構是值類型,因此它們被分配在堆棧上。 然而,它們也可以被復制到堆中,例如將它們存儲在引用類型中。

class Test1
{
    private Foo Foo = new();
}

unsafe struct Foo
{
    public fixed int bar[10];
}

上面的代碼將被編譯並且私有Foo實例將存在於托管堆中。

如果沒有固定語句(只是一個“正常”的 int[]),數組的數據將不會存儲在結構本身中,而是存儲在堆中。 該結構將只擁有對該數組的引用。

使用stackalloc ,數據在堆棧上分配,不能由 CLR 自動移動到堆中。 這意味着堆棧分配的數據保留在堆棧上,編譯器將通過不允許這樣的代碼來強制執行此操作:

unsafe class Test1
{
    // CS8345: Field or auto-implemented property cannot be of type 'Span<int>' unless it is an instance member of a ref struct.

    private Span<int> mySpan;

    public Test1()
    {
        // CS8353: A result of a stackalloc expression of type 'Span<int>' cannot be used in this context because it may be exposed outside of the containing method
        mySpan = stackalloc int[10];
    }
}

因此,當您絕對想確保分配的數據不能逃逸到堆中時,您可以使用stackalloc ,從而導致抓取收集器的壓力增加(這是一個性能問題)。 另一方面, fixed主要用於與本機C/C++庫的互操作場景,這些庫可能出於某種原因使用內聯緩沖區。 因此,當從本機世界調用將帶有內聯緩沖區的結構作為參數的方法時,您必須能夠在 .NET 中重新創建它,否則您將無法輕松使用本機代碼(因此存在fixed語句)。 使用fixed另一個原因是內聯結構中的數據,這可以在 CPU 訪問它時進行更好的緩存,因為它可以一次性讀取Foo中的所有數據,而無需取消引用引用並在內存中跳轉訪問存儲在別處的一些數組。

暫無
暫無

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

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