就我而言,以下代碼將在堆疊上創建一個陣列:
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 說固定大小的緩沖區用于與其他平臺“互操作”。那么這個“互操作”是什么樣子的呢?
uj5u.com熱心網友回復:
該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 一次性無需取消參考參考并在記憶體中跳轉以訪問存盤在其他地方的某些陣列。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/358410.html
