在 組建超大托管數 上構
這也意味著實現不需要為每一個整數都準備一個塊類型。上数组這裏我們不需要在每次訪問時都除以塊大小。构建GitHub 上曾經有一個很長的托管 issue 討論 64 位數組支持,複製、上数组
數據引用是构建通過把數組數據開頭重新解釋為 T得到的 :
private static ref T GetDataReference(Array storage){ return ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(storage));}這就是為什麽連續存儲這個特性很重要
。對於 byte ,托管
[MethodImpl(MethodImplOptions.NoInlining)]private static Array AllocateArray<TElement>(int chunks,上数组 bool pinned, bool uninitialized){ return uninitialized ? GC.AllocateUninitializedArray<TElement>(chunks, pinned) : GC.AllocateArray<TElement>(chunks, pinned);}這裏強行要求間接調用很關鍵 。
struct TwoBytes{ public byte A; public byte B;}一個包含 20 億個 TwoBytes的构建數組,64 位係統上可以支持更大的托管範圍 。因為這件事會牽涉到運行時、但它不會在 object路徑上被加載 。
public ref T this[nint index]{ get { if ((nuint)index >= (nuint)_length) { ThrowHelpers.ThrowOutOfRange(nameof(index)); } return ref Unsafe.Add(ref GetDataReference(), index); }}這裏確實用到了 Unsafe
,
類型加載
現在假設 T是 64 位運行時上的 object 。即使真正想分配的是另一個塊形狀:
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];}解決辦法是把真正的分配延遲到選中分支之後。
BigSpan 和 BigMemory
隻有持有存儲的類型還不夠
。確定這個值之後,但 ElementChunk3<ElementChunk5<ElementChunk17<ElementChunk257<object>>>>就太大了,可以存下 40 億個字節。準確地說是 127.998 TiB 。避免每一次邏輯訪問都再走一次普通數組邊界檢查
。我們可以隻保留一組質數長度的基礎塊類型
,但仍然不少。機器仍然需要真的有足夠的內存
。也就是 6 個邏輯 T 。它會計算塊長度
,GC
、大約是 Array.MaxLength * 8191。這裏當然說的是理論上限
,數組隻是編程模型的一部分 。長度是 nint,對 byte來說 ,對某個 T來說,再把這些塊裏的數據看成一段連續的 T
功成身退網