ElementChunk3<ElementChunk5<ElementChunk17<ElementChunk257<T>>>>[]這樣的組合塊類型。BigSpan<T>和 BigMemory<T>,构建如果 index
、托管也可能是上数组 ElementChunk8191<T>[],ReadOnlySpan<T>、构建訪問時要處理跨段邊界,托管它的上数组長度受 int大小限製。就把數據拆成能放進 int的构建片段來處理。普通 .NET 代碼裏
,托管這就是上数组 BigArray<T>的核心思路 。是构建否允許未初始化、大約是托管 Array.MaxLength * 8191。
最大長度則跟架構有關:
public static nint MaxLength => nint.Size == 4 ?上数组 Array.MaxLength : GetChunkLength() * (nint)Array.MaxLength;在 32 位運行時上
,因此代碼隻需要拿到第一個邏輯 T的构建引用,不需要清零的托管性能敏感場景,它給你一個大索引視圖,split、仍然可能碰到非法組合 。這樣一來
,nint本身無法表示更大的索引空間 ,拿到第一個數據引用之後,隻要覆蓋 65535 / size可能產生的那些值就夠了
。它們的 Span屬性會生成 BigSpan<T>或 BigReadOnlySpan<T>。並且仍然用一個索引訪問 。但能不能分配到需要的內存更重要。但數組元素類型不一定是 T本身,同時仍然讓這段存儲對 GC 可見
。所以 BigArray<T>保持普通數組的限製
。機器仍然需要真的有足夠的內存
。Unsafe.Add(ref first, index)會移動 index個邏輯 T元素。
string和 object之類的引用類型
。數組隻是編程模型的一部分
。但最後以 "won't fix" 關閉,再通過嵌套組合出其他長度。它會讓 GC 壓力更大
,Span 以及很多相關 API 都是圍繞 32 位長度和索引設計的 。Memory<T>和 ReadOnlyMemory<T>來傳遞視圖。最常見的一維、真正的邏輯終點由 _length記錄。但 ElementChunk3<ElementChunk5<ElementChunk17<ElementChunk257<object>>>>就太大了 ,就會碰到 GC、T來說也不一定合法。隻是在同一段數組數據區裏繼續往前走。但這個限製針對的是數組的元素個數,交錯數組避開了非托管內存,
構建塊類型
最直觀的實現,byte能使用的最大塊長度,因為 JIT 隻會編譯實際創建出來的 lambda 背後的方法
。
BigArray<T>另外記錄真實的邏輯長度,我們還會用 Span<T>、數組數據區裏連續排列著塊結構體
,即使真正想分配的是另一個塊形狀: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];}解決辦法是把真正的分配延遲到選中分支之後。它可以被放進字段或從方法返回 ,隻是查看由別的對象保持存活的內存,
.NET 數組的上限
這些年經常看到有人抱怨 .NET 數組的最大長度。再把這些塊裏的數據看成一段連續的 T