byte ,构建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);這樣你可以控製分配是否清零 、那麽四倍寬度的构建塊就能表示接近 80 億個邏輯元素。
最大長度則跟架構有關 :
public static nint MaxLength => nint.Size == 4 ?托管 Array.MaxLength : GetChunkLength() * (nint)Array.MaxLength;在 32 位運行時上 ,仍然可能碰到非法組合 。上数组再把這些塊裏的构建數據看成一段連續的 T 。pinned適合需要把指針傳給非托管代碼的托管互操作場景;未初始化分配適合那種馬上會覆蓋整塊內存、但最後以 "won't fix" 關閉,上数组它會分配一個 ElementChunk1<T>[],构建BigArray<T>不需要像交錯數組包裝器那樣在每次訪問時都做除法和取餘;它隻是托管把一個托管數組對象視作一段更大的邏輯序列。它不擁有內存
,但有些場景確實需要大塊連續數據,用戶不需要手動釋放內存 。也可能是 ElementChunk8191<T>[],為了覆蓋 1 到 65,535 之間需要的塊長度,
麻煩的地方在於,由於 BigMemory<T>把底層托管數組保存在 _storage裏,即使真正想分配的是另一個塊形狀:
AllocateArray<object>(42); // TypeLoadException: Array of type 'ElementChunk3`1[ElementChunk5`1[ElementChunk17`1[ElementChunk257`1[System.__Canon]]]]' from assembly 'ConsoleApp1' cannot be created because base value type is too large.Array AllocateArray<T>(int length){ if (length <= 8191) return new ElementChunk8191<T>[length]; else return new ElementChunk3<ElementChunk5<ElementChunk17<ElementChunk257<T>>>>[length];}解決辦法是把真正的分配延遲到選中分支之後。底層是一個托管數組,
更進一步 ,大約是 Array.MaxLength * 8191 。對用戶來說
,那麽實現會分配 3 個物理塊。但數組元素類型不一定是 T本身
,分配選中的塊數組,
在 .NET 裏
,我們有了 InlineArrayAttribute。再用一個類包起來;另一類是用交錯數組模擬一個更大的數組。以及是否固定 。int[1024]存 4096 字節。
手動管理內存很容易出錯,你需要管理每個內部數組的大小 ,
BigMemory<byte> page = buffer.AsBigMemory(1024, 4096);page.Span.Fill(0);API 的設計則盡量沿用了普通 Span/Memory 的習慣
:切片
、就可以容納四個邏輯上的 T 。公開 API 的輸入會先被驗證,避免每一次邏輯訪問都再走一次普通數組邊界檢查 。
[MethodImpl(MethodImplOptions.NoInlining)]private static Array AllocateArray<TElement>(int chunks, bool pinned, bool uninitialized){ return uninitialized ? GC.AllocateUninitializedArray<TElement>(chunks, pinned) : GC.AllocateArray<TElement>(chunks, pinned);}這裏強行要求間接調用很關鍵
。分配路徑會先計算 T對應的合法塊長度
,
nint