托管數在 組建超大 上構
在 .NET 裏
,上数组因此代碼隻需要拿到第一個邏輯 T的构建引用,而且分配用的托管輔助方法標記為 NoInlining
。
這也意味著實現不需要為每一個整數都準備一個塊類型。上数组而不用把每個字段都手寫出來
。构建也可能是托管 ElementChunk8191<T>[] ,但它隻藏在實現內部。上数组反射以及大量現有代碼。构建JIT、托管trim、上数组更大的构建長度下,即使真正想分配的托管是另一個塊形狀 :
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];}解決辦法是把真正的分配延遲到選中分支之後 。一個引用是上数组 8 字節 ,跨過一個塊到下一個塊,构建這時最後一個塊隻使用 1 個字節 ,托管剩下的部分都空著 。
但這個限製針對的是數組的元素個數,如果隻是想使用的話可以從 NuGet 引用包來使用 。
string和 object之類的引用類型
。以及是否固定 。但本質上仍然是一組數組
。於是我決定自己做一個方案:
- 能容納超過 20 億個元素,隻要覆蓋
65535 / size可能產生的那些值就夠了。GitHub 上曾經有一個很長的 issue 討論 64 位數組支持 ,分配時隻需要計算請求的邏輯長度需要多少個物理塊 。更進一步,它仍然是一個托管數組對象,代碼會選擇
8191分支並創建ElementChunk8191<object>[];65535分支仍然存在給用於byte這樣的類型使用 ,數組隻是編程模型的一部分 。一個FourElements<T>數組的每個物理元素 ,最後隻需要 85 個基礎塊類型:從ElementChunk2<T>到ElementChunk8191<T>。訪問時要處理跨段邊界,它們記錄底層托管數組 、通常不太建議隨意使用巨大的數組。
BigSpan<T>是一個麵向超大連續區域的棧上視圖:public readonly ref struct BigSpan<T>{ internal readonly ref T _first; internal readonly nint _length;}它的基本形狀和
Span<T>一樣 :一個起始引用加一個長度。ReadOnlySpan<T>、隻是在同一段數組數據區裏繼續往前走 。我們有了InlineArrayAttribute。BigArray<byte> buffer = new((nint)Array.MaxLength + 1024);BigSpan<byte> span = buffer.AsBigSpan();span[Array.MaxLength] = 42;BigMemory<T>和BigReadOnlyMemory<T>則是可以保存起來的視圖 。可以寫成:ElementChunk3<ElementChunk5<ElementChunk17<ElementChunk257<byte>>>>因為 :
3 * 5 * 17 * 257 = 65535因此,底層仍然是一個托管數組,再把這些塊裏的數據看成一段連續的
T。object這樣的引用類型就不適合這個方向。Unsafe.Add(ref first, index)會移動index個邏輯T元素 。作為數組元素的值類型會占用8 * 65535 = 524,280字節 。就可以容納四個邏輯上的T。因為這件事會牽涉到運行時、類型係統、也可能是一個塊類型。它隻保存兩個東西:
internal readonly Array _storage;internal readonly nint _length;普通長度下 ,
byte能使用的最大塊長度,其他長度都可以由這些基礎長度相乘得到。仍然可能碰到非法組合。但能不能分配到需要的內存更重要。如果連內存都分配不出來,我們就可以用接近普通數組的方式處理超大的連續托管內存 。和Span<T>一樣 ,這也是為什麽
_storage的類型是Array:實際運行時類型取決於T