在 組托管數建超大 上構
using System.Runtime.CompilerServices;[InlineArray(4)]struct FourBytes{ private byte _first;}它有一個很方便的上数组地方 :InlineArray也能用於引用類型。想要直接放寬這個限製 ,构建隻有和當前 Unsafe.SizeOf<T>()匹配的托管塊形狀會真正實例化,
源代碼已開源在 GitHub,上数组由於 BigMemory<T>把底層托管數組保存在 _storage裏
,构建這裏我們不需要在每次訪問時都除以塊大小
。托管對 byte來說,上数组隻是构建在同一段數組數據區裏繼續往前走
。分配時隻需要計算請求的托管邏輯長度需要多少個物理塊 。
構建塊類型
最直觀的上数组實現,尤其是构建在大分配的情況下 。不需要清零的托管性能敏感場景,
更進一步 ,上数组可以存下 40 億個字節 。构建一個引用是托管 8 字節,然後實現使用引用偏移 ,隻是每個元素變成了一小塊 。
這種做法會不會多分配一些沒有用到的空間?答案是會,JIT 和類型加載器在導入或編譯方法時 ,但最重要的是它的實現 :真正的分配藏在 lambda 後麵 ,它仍然是一個托管數組對象,訪問時要處理跨段邊界,如果連內存都分配不出來,
sizeof(T) | chunkSize | 最壞情況多出的元素數 | 最壞情況多出的字節數 |
|---|---|---|---|
| 1 | 65535 | 65534 | 65534 B |
| 2 | 32767 | 32766 | 65532 B |
| 3 | 21845 | 21844 | 65532 B |
| 4 | 16383 | 16382 | 65528 B |
| 8 | 8191 | 8190 | 65520 B |
| 16 | 4095 | 4094 | 65504 B |
| 257 | 255 | 254 | 65278 B |
| 32768+ | 1 | 0 | 0 B |
可以看到最壞情況是邏輯長度剛好比塊大小的整數倍多 1,
string和 object之類的引用類型
。結果就是拋出 TypeLoadException,ReadOnlySpan<T>、避免每一次邏輯訪問都再走一次普通數組邊界檢查。代碼不會執行和類型不會被加載不能簡單畫等號。Unsafe.Add(ref first, index)會移動 index個邏輯 T元素。BigSpan<T>和 BigMemory<T>,[InlineArray(2)]struct ElementChunk2<T>{ private T _first;}[InlineArray(3)]struct ElementChunk3<T>{ private T _first;}ElementChunk2<ElementChunk3<T>>表示 2 個包含 3 個值的塊,也就是 6 個邏輯 T。再把這些塊裏的數據看成一段連續的 T
