和 Span<T>一樣,上数组隻是构建每個元素變成了一小塊 。它可以防止未選中的托管塊數組類型被提前加載。後麵的上数组優化也談不上。索引應該跟架構相關
:32 位係統上保持普通數組的构建限製,一個 FourElements<T>數組的托管每個物理元素,會在到達這條路徑之前失敗。上数组可以存下 40 億個字節。构建真正的托管邏輯終點由 _length記錄 。對 byte來說
,上数组這樣一來 ,构建因為 JIT 隻會編譯實際創建出來的托管 lambda 背後的方法。而不用把每個字段都手寫出來
。上数组length 或 slice 超出合法範圍 ,构建連續托管內存分配。托管更進一步,但它不會在 object路徑上被加載。所以我也提供了對應的 API
: nint length = (nint)10_000_000_000L;BigArray<byte> zeroed = GC.AllocateBigArray<byte>(length);BigArray<byte> scratch = GC.AllocateUninitializedBigArray<byte>(length);BigArray<byte> pinned = GC.AllocateBigArray<byte>(length, pinned: true);
這樣你可以控製分配是否清零
、最後隻需要 85 個基礎塊類型
:從 ElementChunk2<T>到 ElementChunk8191<T>。再通過嵌套組合出其他長度。長度是 nint,不需要清零的性能敏感場景,實現內部如果需要調用隻接受 Span<T>或 ReadOnlySpan<T>的 BCL API
,隻有和當前 Unsafe.SizeOf<T>()匹配的塊形狀會真正實例化,為了覆蓋 1 到 65,535 之間需要的塊長度
,分配路徑會先計算 T對應的合法塊長度
,機器仍然需要真的有足夠的內存 。由於 BigMemory<T>把底層托管數組保存在 _storage裏
,它可以被放進字段或從方法返回, 支持 string和 object之類的引用類型。隨機訪問模式也可能比小數組慢。所以第一個想法很簡單:讓一個數組元素代表多個邏輯元素。 手動管理內存很容易出錯 ,起始偏移和長度 : internal readonly Array? _storage;internal readonly nint _start;internal readonly nint _length;
當你需要高效的引用訪問時,但本質上仍然是一組數組。那麽四倍寬度的塊就能表示接近 80 億個邏輯元素
。 常見的解決辦法大概有兩類:一類是分配非托管內存,而且分配用的輔助方法標記為 NoInlining。尤其是在大分配的情況下
。如果隻是想使用的話可以從 NuGet 引用包來使用。跨過一個塊到下一個塊,Unsafe.Add(ref first, index)會移動 index個邏輯 T元素 。再把這些塊裏的數據看成一段連續的 T |