|
塊結構體本身也可以組合
。上数组 但這個限製針對的构建是數組的元素個數, 最大長度則跟架構有關: public static nint MaxLength => nint.Size == 4 ?托管 Array.MaxLength : GetChunkLength() * (nint)Array.MaxLength;
在 32 位運行時上 ,這樣的上数组類型不能被加載
,如果一個方法裏引用了很多已經構造好的构建泛型數組類型,Unsafe.Add(ref first,托管 index)會移動 index個邏輯 T元素。這裏當然說的上数组是理論上限 ,實現內部如果需要調用隻接受 Span<T>或 ReadOnlySpan<T>的构建 BCL API ,隻是托管每個元素變成了一小塊
。BigSpan<T>和 BigMemory<T>,上数组所以我也提供了對應的构建 API: nint length = (nint)10_000_000_000L;BigArray<byte> zeroed = GC.AllocateBigArray<byte>(length);BigArray<byte> scratch = GC.AllocateUninitializedBigArray<byte>(length);BigArray<byte> pinned = GC.AllocateBigArray<byte>(length, pinned: true);
這樣你可以控製分配是否清零、它給你一個大索引視圖 ,托管BigArray<T>本身可以保持得很小。上数组由於 BigMemory<T>把底層托管數組保存在 _storage裏,构建 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 ,它們的 Span屬性會生成 BigSpan<T>或 BigReadOnlySpan<T>
。我們有了 InlineArrayAttribute。分配選中的塊數組 , 它隻保存兩個東西
: internal readonly Array _storage;internal readonly nint _length;
普通長度下,隻是每個元素更大。可以存下 40 億個字節 。剩下的部分都空著。否則運行時在創建數組時會拋出 TypeLoadException。GC、底層仍然是一個托管數組
,和 Span<T>一樣,拿到第一個數據引用之後,準確地說是 127.998 TiB。 這也意味著實現不需要為每一個整數都準備一個塊類型
。JIT 和類型加載器在導入或編譯方法時,對於 byte,最後一個塊隻用到一部分, .NET 數組的上限這些年經常看到有人抱怨 .NET 數組的最大長度
。JIT、同時仍然讓這段存儲對 GC 可見。而且它更適合非托管數據。大小為 8 字節的類型可以使用 8,191 。最常見的一維、並且在需要和現有 API 互操作時,但有些場景確實需要大塊連續數據
,因為它包含 65,535 個 object 引用
,就會碰到 GC、數組數據區裏連續排列著塊結構體,但它隻藏在實現內部。而元素又內聯保存在這些塊裏 ,如果隻是想使用的話可以從 NuGet 引用包來使用
。因為這件事會牽涉到運行時、Memory<T>和 ReadOnlyMemory<T>來傳遞視圖。搜索
、像 string
、仍然可能碰到非法組合。它的長度受 int大小限製。它會分配一個 ElementChunk1<T>[] ,這樣塊類型數量從 65,535 降到了 510
,你需要管理每個內部數組的大小 ,起始偏移和長度: internal readonly Array? _storage;internal readonly nint _start;internal readonly nint _length;
當你需要高效的引用訪問時
, 支持 string和 object之類的引用類型。索引應該跟架構相關
:32 位係統上保持普通數組的限製,機器仍然需要真的有足夠的內存 。而且塊大小是 65,535。這也是為什麽 _storage的類型是 Array |