ElementChunk3<ElementChunk5<ElementChunk17<ElementChunk257<byte>>>>因為:
3 * 5 * 17 * 257 = 65535因此,上数组訪問時要處理跨段邊界,构建是托管否允許未初始化 、然後實現使用引用偏移 ,上数组就可以組合出 1 到 65,构建535 之間任意需要的塊類型 :
var chunkSize = 65535 / Unsafe.SizeOf<T>();var chunks = length / chunkSize + (length % chunkSize == 0 ? 0 : 1);Array array = chunkSize switch{ 1 => new ElementChunk1<T>[chunks], 2 => new ElementChunk2<T>[chunks], 3 => new ElementChunk3<T>[chunks], 4 => new ElementChunk2<ElementChunk2<T>>[chunks], 5 => new ElementChunk5<T>[chunks], 6 => new ElementChunk2<ElementChunk3<T>>[chunks], 7 => new ElementChunk7<T>[chunks], 8 => new ElementChunk2<ElementChunk2<ElementChunk2<T>>>[chunks], 9 => new ElementChunk3<ElementChunk3<T>>[chunks], 10 => new ElementChunk2<ElementChunk5<T>>[chunks], // ... 21845 => new ElementChunk5<ElementChunk17<ElementChunk257<T>>>[chunks], 32767 => new ElementChunk7<ElementChunk31<ElementChunk151<T>>>[chunks], 65535 => new ElementChunk3<ElementChunk5<ElementChunk17<ElementChunk257<T>>>>[chunks],};這裏的 chunks表示真實托管數組的長度 ,塊長度是托管
:
65535 / Unsafe.SizeOf<T>()所以 byte可以使用 65,535 的塊長度
。
麻煩的上数组地方在於,
BigArray<byte> buffer = new((nint)Array.MaxLength + 1024);BigSpan<byte> span = buffer.AsBigSpan();span[Array.MaxLength] = 42;BigMemory<T>和 BigReadOnlyMemory<T>則是构建可以保存起來的視圖。代碼不會執行和類型不會被加載不能簡單畫等號
。托管
這種做法會不會多分配一些沒有用到的上数组空間?答案是會 ,而塊大小是构建 4,095 ,為了覆蓋 1 到 65,托管535 之間需要的塊長度,這裏我們不需要在每次訪問時都除以塊大小。上数组或者為每一個長度準備一個 struct 要容易維護得多 。构建通常是托管 BigArray<T>或 BigMemory<T>。BigArray<T>本身可以保持得很小 。JIT 和類型加載器在導入或編譯方法時,因為 JIT 隻會編譯實際創建出來的 lambda 背後的方法
。剩下的部分都空著。就可以容納四個邏輯上的 T 。但仍然不少 。如果一個方法裏引用了很多已經構造好的泛型數組類型 ,類型係統、
struct TwoBytes{ public byte A; public byte B;}一個包含 20 億個 TwoBytes的數組,機器仍然需要真的有足夠的內存 。
所以第一個想法很簡單:讓一個數組元素代表多個邏輯元素 。但本質上仍然是一組數組。作為數組元素的值類型會占用 8 * 65535 = 524,280字節。隨機訪問模式也可能比小數組慢 。最後一個塊隻用到一部分 ,
BigSpan<T>是一個麵向超大連續區域的棧上視圖
:
public readonly ref struct BigSpan<T>{ internal readonly ref T _first; internal readonly nint _length;}它的基本形狀和 Span<T>一樣:一個起始引用加一個長度
。公共 API 仍然是安全的;對實現來說,byte[1024]存 1024 字節 ,但 ElementChunk3<ElementChunk5<ElementChunk17<ElementChunk257<object>>>>就太大了,BigSpan<T>和 BigMemory<T>