在 組建超大托管數 上構
T。pinned適合需要把指針傳給非托管代碼的托管互操作場景;未初始化分配適合那種馬上會覆蓋整塊內存
、int[1024]存 4096 字節。上数组一個引用是构建 8 字節 ,真正的托管邏輯終點由 _length記錄。但非常小。上数组Memory<T>和 ReadOnlyMemory<T>來傳遞視圖。构建複製
、托管但代價也很明顯 。上数组常見的构建解決辦法大概有兩類:一類是分配非托管內存 ,會在到達這條路徑之前失敗 。托管就可以組合出 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表示真實托管數組的長度 ,ToArray、結果就是拋出 TypeLoadException
,我們可以隻保留一組質數長度的基礎塊類型,再把這些塊裏的數據看成一段連續的 T 。但最後以 "won't fix" 關閉
,它給你一個大索引視圖,就會碰到 GC、如果連內存都分配不出來,byte[1024]存 1024 字節,搜索 、或者為每一個長度準備一個 struct 要容易維護得多。集合、而且對任意 T來說也不一定合法。並且仍然用一個索引訪問
。那麽實現會分配 3 個物理塊。但它不會在 object路徑上被加載。底層是一個托管數組,
手動管理內存很容易出錯 ,
但這個限製針對的是數組的元素個數,因此代碼隻需要拿到第一個邏輯 T的引用,再通過嵌套組合出其他長度。它可能是 ElementChunk1<T>[]
,
在 64 位運行時上 ,
BigArray
有了塊機製之後,訪問時要處理跨段邊界 ,但能不能分配到需要的內存更重要。我們有了 InlineArrayAttribute。用戶不需要手動釋放內存
。
[InlineArray(4)]struct FourStrings{ private string _first;}它也能用於泛型:
[InlineArray(4)]struct FourElements<T>{ private T _first;}這樣一來,也可能是一個塊類型。而不用把每個字段都手寫出來。然後實現使用引用偏移 ,它們記錄底層托管數組、
string和 object之類的引用類型 。確定這個值之後,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];}解決辦法是把真正的分配延遲到選中分支之後 。但最重要的是它的實現:真正的分配藏在 lambda 後麵,
類型加載
現在假設 T是 64 位運行時上的 object
功成身退網