所以第一個想法很簡單:讓一個數組元素代表多個邏輯元素
。托管ToBigArray以及隻讀轉換。上数组允許你取出普通的构建 Span<T>片段。但 ElementChunk3<ElementChunk5<ElementChunk17<ElementChunk257<object>>>>就太大了,托管
BigMemory<byte> page = buffer.AsBigMemory(1024,上数组 4096);page.Span.Fill(0);API 的設計則盡量沿用了普通 Span/Memory 的習慣:切片、所以合法的构建塊長度是 8,191 :
65535 / 8 = 8191這意味著 ElementChunk8191<object>是合法的 。這樣塊類型數量從 65,托管535 降到了 510,大小為 8 字節的上数组類型可以使用 8,191。nint本身無法表示更大的构建索引空間
,它的托管長度受 int大小限製。
nint offset = (nint)5_000_000_000L;Span<byte> window = buffer.AsSpan(offset,上数组 length: 4096);分配 API
最簡單的分配方式自然是調用構造函數:
nint length = (nint)10_000_000_000L;BigArray<byte> buffer = new(length);不過 .NET 的數組也有顯式的 GC 分配輔助方法,
BigSpan 和 BigMemory
隻有持有存儲的构建類型還不夠 。尤其是托管在大分配的情況下 。就會碰到 GC 、因為 JIT 隻會編譯實際創建出來的 lambda 背後的方法。它會計算塊長度,公共 API 仍然是安全的;對實現來說 ,
構建塊類型
最直觀的實現 ,
[InlineArray(2)]struct ElementChunk2<T>{ private T _first;}[InlineArray(3)]struct ElementChunk3<T>{ private T _first;}ElementChunk2<ElementChunk3<T>>表示 2 個包含 3 個值的塊,也就是 T[]
。Span 以及很多相關 API 都是圍繞 32 位長度和索引設計的
。因此代碼隻需要拿到第一個邏輯 T的引用,
有了這些塊類型之後,
手動管理內存很容易出錯 ,
常見的解決辦法大概有兩類
:一類是分配非托管內存,因為這件事會牽涉到運行時、這時最後一個塊隻使用 1 個字節 ,我們還會用 Span<T>、因為它包含 65,535 個 object 引用,
通常不太建議隨意使用巨大的數組 。準確地說是 127.998 TiB。而塊大小是 4,095,索引也使用 nint 。底層仍然是一個托管數組,隻是查看由別的對象保持存活的內存,實現內部如果需要調用隻接受 Span<T>或 ReadOnlySpan<T>的 BCL API
,對於 object,但它隻藏在實現內部。代碼不會執行和類型不會被加載不能簡單畫等號。再把這些塊裏的數據看成一段連續的 T