この記事は .NET6 Advent Calendar 2021 の14日目の記事です。
.NET6 におけるバッファメモリ確保
以前 .NET Framework4.8 でメモリ確保の方法についてベンチマークを取り、記事にしたことがあります。 (参考 (C#) メモリ確保ベンチマーク 6種盛り)
.NET6 でいろいろとバージョンアップしているので、.NET6 でベンチマークを取ってみました。 前回は6通りの方法を試しましたが、今回は新たに追加されたメソッドを含めて7通りを試します。
ベンチマークライブラリはいつも通り BenchmarkDotNet を使用します。
// (1) [Benchmark(Baseline = true, Description = "new byte[]")] public byte[] NewAlloc() { return new byte[Size]; } // (2) [Benchmark(Description = "ArrayPool")] public void SharedPool() { var array = ArrayPool<byte>.Shared.Rent(Size); ArrayPool<byte>.Shared.Return(array); } // (3) [Benchmark(Description = "Marshal.Alloc")] public void MarshalAlloc() { var array = Marshal.AllocHGlobal(Size); Marshal.FreeHGlobal(array); } // (4) [Benchmark(Description = "Marshal.Alloc + GCPressure")] public void MarshalAlloc_WithGCPressure() { var array = Marshal.AllocHGlobal(Size); GC.AddMemoryPressure(Size); Marshal.FreeHGlobal(array); GC.RemoveMemoryPressure(Size); } // (5) [Benchmark(Description = "NativeMemory.Alloc")] public unsafe void NativeAlloc() { var array = NativeMemory.Alloc((nuint)Size); NativeMemory.Free(array); } // (6) [Benchmark(Description = "NativeMemory.Alloc + GCPressure")] public unsafe void NativeAlloc_WithGCPressure() { var array = NativeMemory.Alloc((nuint)Size); GC.AddMemoryPressure(Size); NativeMemory.Free(array); GC.RemoveMemoryPressure(Size); } // (7) [Benchmark(Description = "GC.AllocateUninitializedArray")] public byte[] UninitializedArray() { return GC.AllocateUninitializedArray<byte>(Size); }
メモリ確保の方法として、それぞれ
- (1)
new byte[N]
- (2)
ArrayPool<byte>.Shared.Rent(N)
- (3)
Marshal.AllocHGlobal(N)
- (4) (3) +
GC.AddMemoryPressure
- (5)
NativeMemory.Alloc(N)
- (6) (5) +
GC.AddMemoryPressure
- (7)
GC.AllocateUninitializedArray<byte>(N)
です。(1), (2), (7) はマネージドメモリ、(3), (4), (5), (6) はアンマネージドメモリです。
ベンチマーク結果
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19042.1415 (20H2/October2020Update) Intel Core i7-10700 CPU 2.90GHz, 1 CPU, 16 logical and 8 physical cores .NET SDK=6.0.100 [Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT RyuJitX64 : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT Job=RyuJitX64 Jit=RyuJit Platform=X64
もっとも単純な (1) の new byte[N]
は、サイズに対してほぼ比例です。
また、(2) の ArrayPool<byte>.Shared.Rent(N)
はサイズによらず定数です。これは、ArrayPool<byte>
の内部プールが定常状態で配列がプールから取り出される場合、N によらず常に同じフローです。
ArrayPoolnew T[]
ではなく GC.AllocateUninitializedArray<byte>(N)
を使用するようになりました。
(3) と (5) はともにアンマネージドメモリを確保しています。
(5) について、以前の .NET Framework4.8 でのベンチマークでは自分でC++で std::malloc
と std::free
をする dll を用意して呼び出していましたが、.NET6 から同様のメソッドが標準ライブラリ入りしたためそちらを使用しています。また、.NET6 で NativeMemory.Alloc(N)
が実装されたことによって (3) の Marshal.AllocHGlobal(N)
も内部で同じものを呼ぶように変更されました。したがって、(3) と (5) は全く同一でグラフも完全に一致しています。
(4) と (6) は (3) と (5) に GC Pressure の操作を追加したもので、その操作にかかる時間だけ時間が多くかかっています。
(7) は .NET6 から新たに追加されたメソッドです。new byte[N]
と同じくマネージドメモリを確保しますが、配列の要素はゼロ初期化されていません。その分だけ (1) よりも速くなっています。ここで注目すべきは、2048 以下の時には (1) とほぼ一致していることです。これは、GC.AllocateUninitializedArray<T>(N)
はサイズが2048バイト未満の場合は内部で new T[N]
を呼び出しており、実装上の都合でその方が速いためとのことです。このメソッドの T は unmanaged 型、つまりプリミティブ型と、再帰的に全てのフィールドがプリミティブ型で構成される構造体でのみ使用可能です。
補足など
GC Pressure について
GC.AddMemoryPressure
については私自身、使いどころがうまく理解できていません。確かにアンマネージドメモリを確保するとメモリ使用量は増えたにもかかわらずランタイムには認知されません。この時、メモリが逼迫するとランタイムはメモリを空けようと GC を走らせますが、実際にはメモリは空かず、逼迫した状態が続くので何度も意味のない GC を連発するようなことが起こるのかもしれません。しかし、もともとネイティブな外部 dll を呼び出して相互運用するようなアプリケーションの場合、ネイティブ側でどれだけメモリが確保されているかなど C# 側からは知る由もなく、GC.AddMemoryPressure
を使うことはできません。これは私の勝手な判断ですが、合計でギガバイト以上の大きなメモリを確保する場合などのメモリが逼迫しうる量を確保しない限り、GC.AddMemoryPressure
を使う必要はないと思っています。(もし GC.AddMemoryPressure
を使うべき明確な理由や場面を知っている方がいれば教えてください)
アンマネージドメモリの使用について
アンマネージドメモリはその名の通りランタイムに管理されていません。利点として GC の対象にならないため停止時間に影響を与えません。一方欠点として解放を忘れるとメモリリークします。C++ や Rust のようにメモリリークを言語レベルで防ぐためのサポートもなく、生のポインタです。一応 IDisposable
に包むと using
構文で自動解放できますが、using
を強制する言語サポートはないため危険度としては同じです。ファイナライザを持つクラスに包むと最後のセーフティーとしてメモリリークはしませんが、GC の停止時間中に解放を行うため停止時間を削減するという目的そのものが無意味になります。ライブラリの中で完結する一時バッファとして実装者が責任を持てる範囲以外では使用すべきでないと思います。
また、GC を持つ C# が Rust や C++ より優れている部分として、メモリの断片化が発生しずらいという利点があります。アンマネージドメモリを多用するとこの利点をつぶします。小規模なメモリを何度もアンマネージドメモリに確保し、さらにそれらが長期間生存するような場面には向きません。
バッファとしての使用は、特別な理由がない限り ArrayPool<byte>.Shared.Rent(N)
を使用すべきでしょう。
[追記]
.NET Framework 4.8 のときの記事とは計測したマシンスペックが異なるため、以前の記事と単純な実行時間での比較はしないでください。あくまで各手法間の比率で見てください。
ベンチマーク結果の詳細
Method | Size | Mean | Error | StdDev | Median | Ratio | RatioSD |
---|---|---|---|---|---|---|---|
'new byte' | 16 | 2.420 ns | 0.0573 ns | 0.0536 ns | 2.418 ns | 1.00 | |
ArrayPool | 16 | 14.197 ns | 0.0241 ns | 0.0214 ns | 14.191 ns | 5.87 | 0.14 |
Marshal.Alloc | 16 | 49.691 ns | 0.0782 ns | 0.0694 ns | 49.684 ns | 20.55 | 0.46 |
'Marshal.Alloc + GCPressure' | 16 | 87.830 ns | 0.1201 ns | 0.1124 ns | 87.784 ns | 36.30 | |
NativeMemory.Alloc | 16 | 49.087 ns | 0.0693 ns | 0.0579 ns | 49.084 ns | 20.34 | 0.47 |
'NativeMemory.Alloc + GCPressure' | 16 | 86.639 ns | 0.1773 ns | 0.1572 ns | 86.568 ns | 35.84 | |
GC.AllocateUninitializedArray | 16 | 1.896 ns | 0.0481 ns | 0.0450 ns | 1.882 ns | 0.78 | 0.03 |
'new byte' | 32 | 2.486 ns | 0.0307 ns | 0.0287 ns | 2.487 ns | 1.00 | |
ArrayPool | 32 | 15.458 ns | 0.0095 ns | 0.0074 ns | 15.456 ns | 6.21 | 0.07 |
Marshal.Alloc | 32 | 49.709 ns | 0.1392 ns | 0.1302 ns | 49.690 ns | 19.99 | 0.24 |
'Marshal.Alloc + GCPressure' | 32 | 87.716 ns | 0.0756 ns | 0.0632 ns | 87.705 ns | 35.28 | |
NativeMemory.Alloc | 32 | 47.426 ns | 0.0657 ns | 0.0582 ns | 47.415 ns | 19.08 | 0.23 |
'NativeMemory.Alloc + GCPressure' | 32 | 85.087 ns | 0.2800 ns | 0.2619 ns | 84.965 ns | 34.22 | |
GC.AllocateUninitializedArray | 32 | 2.411 ns | 0.0358 ns | 0.0334 ns | 2.405 ns | 0.97 | 0.02 |
'new byte' | 64 | 3.417 ns | 0.0667 ns | 0.0624 ns | 3.436 ns | 1.00 | |
ArrayPool | 64 | 14.707 ns | 0.0244 ns | 0.0217 ns | 14.699 ns | 4.30 | 0.08 |
Marshal.Alloc | 64 | 53.475 ns | 0.0520 ns | 0.0434 ns | 53.472 ns | 15.63 | 0.29 |
'Marshal.Alloc + GCPressure' | 64 | 89.940 ns | 0.0665 ns | 0.0589 ns | 89.923 ns | 26.28 | |
NativeMemory.Alloc | 64 | 46.917 ns | 0.1785 ns | 0.1670 ns | 46.901 ns | 13.73 | 0.23 |
'NativeMemory.Alloc + GCPressure' | 64 | 85.983 ns | 0.0746 ns | 0.0582 ns | 85.990 ns | 25.15 | |
GC.AllocateUninitializedArray | 64 | 3.381 ns | 0.0779 ns | 0.0728 ns | 3.389 ns | 0.99 | 0.03 |
'new byte' | 128 | 5.155 ns | 0.0990 ns | 0.0926 ns | 5.165 ns | 1.00 | |
ArrayPool | 128 | 15.444 ns | 0.0326 ns | 0.0305 ns | 15.426 ns | 3.00 | 0.05 |
Marshal.Alloc | 128 | 50.599 ns | 0.0346 ns | 0.0270 ns | 50.603 ns | 9.80 | 0.19 |
'Marshal.Alloc + GCPressure' | 128 | 89.218 ns | 0.0967 ns | 0.0905 ns | 89.204 ns | 17.31 | |
NativeMemory.Alloc | 128 | 47.705 ns | 0.1220 ns | 0.1081 ns | 47.667 ns | 9.25 | 0.17 |
'NativeMemory.Alloc + GCPressure' | 128 | 89.048 ns | 0.0671 ns | 0.0628 ns | 89.063 ns | 17.28 | |
GC.AllocateUninitializedArray | 128 | 5.120 ns | 0.0627 ns | 0.0489 ns | 5.142 ns | 0.99 | 0.02 |
'new byte' | 256 | 8.876 ns | 0.1177 ns | 0.1101 ns | 8.898 ns | 1.00 | |
ArrayPool | 256 | 14.331 ns | 0.2157 ns | 0.1912 ns | 14.230 ns | 1.61 | 0.03 |
Marshal.Alloc | 256 | 50.962 ns | 0.3189 ns | 0.2983 ns | 50.958 ns | 5.74 | 0.07 |
'Marshal.Alloc + GCPressure' | 256 | 91.727 ns | 0.7887 ns | 0.7378 ns | 91.540 ns | 10.34 | |
NativeMemory.Alloc | 256 | 47.855 ns | 0.1256 ns | 0.1175 ns | 47.818 ns | 5.39 | 0.07 |
'NativeMemory.Alloc + GCPressure' | 256 | 88.592 ns | 0.0957 ns | 0.0848 ns | 88.622 ns | 9.98 | |
GC.AllocateUninitializedArray | 256 | 8.880 ns | 0.1124 ns | 0.1051 ns | 8.934 ns | 1.00 | 0.02 |
'new byte' | 512 | 16.057 ns | 0.3431 ns | 0.3210 ns | 15.960 ns | 1.00 | |
ArrayPool | 512 | 14.185 ns | 0.0184 ns | 0.0172 ns | 14.177 ns | 0.88 | 0.02 |
Marshal.Alloc | 512 | 50.141 ns | 0.0323 ns | 0.0270 ns | 50.139 ns | 3.13 | 0.07 |
'Marshal.Alloc + GCPressure' | 512 | 100.263 ns | 0.0938 ns | 0.0831 ns | 100.267 ns | 6.25 | |
NativeMemory.Alloc | 512 | 48.371 ns | 0.0636 ns | 0.0595 ns | 48.379 ns | 3.01 | 0.06 |
'NativeMemory.Alloc + GCPressure' | 512 | 96.198 ns | 0.0923 ns | 0.0863 ns | 96.201 ns | 5.99 | |
GC.AllocateUninitializedArray | 512 | 16.169 ns | 0.2531 ns | 0.2367 ns | 16.236 ns | 1.01 | 0.02 |
'new byte' | 1024 | 30.097 ns | 0.4235 ns | 0.3961 ns | 30.006 ns | 1.00 | |
ArrayPool | 1024 | 14.679 ns | 0.0093 ns | 0.0073 ns | 14.679 ns | 0.49 | 0.01 |
Marshal.Alloc | 1024 | 50.266 ns | 0.0349 ns | 0.0309 ns | 50.269 ns | 1.67 | 0.02 |
'Marshal.Alloc + GCPressure' | 1024 | 108.525 ns | 0.0833 ns | 0.0739 ns | 108.522 ns | 3.61 | |
NativeMemory.Alloc | 1024 | 47.416 ns | 0.0289 ns | 0.0270 ns | 47.405 ns | 1.58 | 0.02 |
'NativeMemory.Alloc + GCPressure' | 1024 | 110.094 ns | 0.0874 ns | 0.0818 ns | 110.103 ns | 3.66 | |
GC.AllocateUninitializedArray | 1024 | 29.920 ns | 0.6143 ns | 0.5746 ns | 29.897 ns | 0.99 | 0.03 |
'new byte' | 2048 | 57.893 ns | 0.9656 ns | 0.8560 ns | 57.662 ns | 1.00 | |
ArrayPool | 2048 | 14.776 ns | 0.0128 ns | 0.0113 ns | 14.773 ns | 0.26 | 0.00 |
Marshal.Alloc | 2048 | 51.905 ns | 0.0445 ns | 0.0395 ns | 51.899 ns | 0.90 | 0.01 |
'Marshal.Alloc + GCPressure' | 2048 | 114.753 ns | 0.1050 ns | 0.0982 ns | 114.727 ns | 1.98 | |
NativeMemory.Alloc | 2048 | 48.999 ns | 0.0228 ns | 0.0202 ns | 49.002 ns | 0.85 | 0.01 |
'NativeMemory.Alloc + GCPressure' | 2048 | 111.208 ns | 0.1044 ns | 0.0872 ns | 111.214 ns | 1.92 | |
GC.AllocateUninitializedArray | 2048 | 58.826 ns | 0.1744 ns | 0.1456 ns | 58.761 ns | 1.02 | 0.02 |
'new byte' | 4096 | 118.348 ns | 2.3840 ns | 2.5508 ns | 117.820 ns | 1.00 | |
ArrayPool | 4096 | 14.677 ns | 0.0147 ns | 0.0138 ns | 14.673 ns | 0.12 | 0.00 |
Marshal.Alloc | 4096 | 50.449 ns | 0.0249 ns | 0.0233 ns | 50.445 ns | 0.43 | 0.01 |
'Marshal.Alloc + GCPressure' | 4096 | 120.027 ns | 0.0595 ns | 0.0465 ns | 120.024 ns | 1.02 | |
NativeMemory.Alloc | 4096 | 47.249 ns | 0.0265 ns | 0.0222 ns | 47.247 ns | 0.40 | 0.01 |
'NativeMemory.Alloc + GCPressure' | 4096 | 115.660 ns | 0.1309 ns | 0.1160 ns | 115.620 ns | 0.98 | |
GC.AllocateUninitializedArray | 4096 | 68.978 ns | 0.1841 ns | 0.1537 ns | 68.998 ns | 0.59 | 0.01 |
'new byte' | 8192 | 241.119 ns | 4.5964 ns | 4.2995 ns | 242.919 ns | 1.00 | |
ArrayPool | 8192 | 18.240 ns | 0.0137 ns | 0.0114 ns | 18.235 ns | 0.08 | 0.00 |
Marshal.Alloc | 8192 | 50.385 ns | 0.0422 ns | 0.0374 ns | 50.369 ns | 0.21 | 0.00 |
'Marshal.Alloc + GCPressure' | 8192 | 120.433 ns | 0.1308 ns | 0.1223 ns | 120.399 ns | 0.50 | |
NativeMemory.Alloc | 8192 | 47.494 ns | 0.0318 ns | 0.0266 ns | 47.487 ns | 0.20 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 8192 | 120.283 ns | 0.0880 ns | 0.0735 ns | 120.262 ns | 0.50 | |
GC.AllocateUninitializedArray | 8192 | 74.431 ns | 0.1530 ns | 0.1277 ns | 74.431 ns | 0.31 | 0.01 |
'new byte' | 16384 | 424.195 ns | 8.2143 ns | 8.7893 ns | 421.584 ns | 1.00 | |
ArrayPool | 16384 | 17.953 ns | 0.0227 ns | 0.0201 ns | 17.943 ns | 0.04 | 0.00 |
Marshal.Alloc | 16384 | 53.502 ns | 0.2266 ns | 0.2119 ns | 53.448 ns | 0.13 | 0.00 |
'Marshal.Alloc + GCPressure' | 16384 | 120.846 ns | 0.1743 ns | 0.1456 ns | 120.775 ns | 0.28 | |
NativeMemory.Alloc | 16384 | 47.405 ns | 0.0418 ns | 0.0371 ns | 47.391 ns | 0.11 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 16384 | 117.896 ns | 0.0476 ns | 0.0371 ns | 117.901 ns | 0.28 | |
GC.AllocateUninitializedArray | 16384 | 94.471 ns | 0.4015 ns | 0.3353 ns | 94.554 ns | 0.22 | 0.00 |
'new byte' | 32768 | 790.026 ns | 15.5811 ns | 15.3027 ns | 796.038 ns | 1.00 | |
ArrayPool | 32768 | 14.225 ns | 0.0072 ns | 0.0060 ns | 14.222 ns | 0.02 | 0.00 |
Marshal.Alloc | 32768 | 137.537 ns | 0.3049 ns | 0.2703 ns | 137.594 ns | 0.17 | 0.00 |
'Marshal.Alloc + GCPressure' | 32768 | 222.805 ns | 0.1789 ns | 0.1673 ns | 222.784 ns | 0.28 | |
NativeMemory.Alloc | 32768 | 139.468 ns | 2.7590 ns | 3.8677 ns | 140.092 ns | 0.17 | 0.01 |
'NativeMemory.Alloc + GCPressure' | 32768 | 216.506 ns | 1.1494 ns | 1.0751 ns | 215.987 ns | 0.27 | |
GC.AllocateUninitializedArray | 32768 | 137.147 ns | 0.2657 ns | 0.2356 ns | 137.163 ns | 0.17 | 0.00 |
'new byte' | 65536 | 1,523.391 ns | 27.7315 ns | 23.1571 ns | 1,532.096 ns | 1.00 | |
ArrayPool | 65536 | 18.432 ns | 0.0124 ns | 0.0104 ns | 18.428 ns | 0.01 | 0.00 |
Marshal.Alloc | 65536 | 109.773 ns | 2.2175 ns | 3.9986 ns | 111.761 ns | 0.07 | 0.00 |
'Marshal.Alloc + GCPressure' | 65536 | 189.097 ns | 3.6164 ns | 3.2059 ns | 190.010 ns | 0.12 | |
NativeMemory.Alloc | 65536 | 105.710 ns | 1.4795 ns | 2.7423 ns | 106.750 ns | 0.07 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 65536 | 185.469 ns | 0.3173 ns | 0.2812 ns | 185.429 ns | 0.12 | |
GC.AllocateUninitializedArray | 65536 | 237.496 ns | 1.2092 ns | 1.0719 ns | 237.694 ns | 0.16 | 0.00 |
'new byte' | 131072 | 4,932.622 ns | 18.8168 ns | 15.7129 ns | 4,933.810 ns | 1.000 | |
ArrayPool | 131072 | 16.016 ns | 0.0116 ns | 0.0103 ns | 16.010 ns | 0.003 | 0.00 |
Marshal.Alloc | 131072 | 119.555 ns | 2.4092 ns | 3.6059 ns | 118.869 ns | 0.025 | 0.00 |
'Marshal.Alloc + GCPressure' | 131072 | 241.775 ns | 4.8540 ns | 12.0883 ns | 246.642 ns | 0.049 | |
NativeMemory.Alloc | 131072 | 112.695 ns | 2.2500 ns | 4.1142 ns | 112.978 ns | 0.023 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 131072 | 203.887 ns | 3.4076 ns | 3.1875 ns | 204.198 ns | 0.041 | |
GC.AllocateUninitializedArray | 131072 | 2,482.482 ns | 8.6712 ns | 7.6868 ns | 2,482.735 ns | 0.503 | 0.00 |
'new byte' | 262144 | 9,745.615 ns | 14.6181 ns | 13.6738 ns | 9,744.838 ns | 1.000 | |
ArrayPool | 262144 | 14.571 ns | 0.0162 ns | 0.0151 ns | 14.564 ns | 0.001 | 0.00 |
Marshal.Alloc | 262144 | 384.751 ns | 26.3435 ns | 76.8453 ns | 409.966 ns | 0.027 | 0.01 |
'Marshal.Alloc + GCPressure' | 262144 | 472.301 ns | 13.4946 ns | 37.6177 ns | 479.022 ns | 0.045 | |
NativeMemory.Alloc | 262144 | 711.295 ns | 76.9815 ns | 217.1276 ns | 796.491 ns | 0.028 | 0.02 |
'NativeMemory.Alloc + GCPressure' | 262144 | 470.812 ns | 4.2143 ns | 3.9421 ns | 470.417 ns | 0.048 | |
GC.AllocateUninitializedArray | 262144 | 5,097.969 ns | 55.8836 ns | 52.2736 ns | 5,096.607 ns | 0.523 | 0.01 |
'new byte' | 524288 | 19,023.374 ns | 144.1437 ns | 134.8321 ns | 19,030.304 ns | 1.000 | |
ArrayPool | 524288 | 16.372 ns | 0.0065 ns | 0.0051 ns | 16.373 ns | 0.001 | 0.00 |
Marshal.Alloc | 524288 | 864.512 ns | 10.9232 ns | 9.6832 ns | 866.815 ns | 0.045 | 0.00 |
'Marshal.Alloc + GCPressure' | 524288 | 662.507 ns | 12.7071 ns | 15.1269 ns | 662.596 ns | 0.035 | |
NativeMemory.Alloc | 524288 | 660.036 ns | 5.1624 ns | 8.3363 ns | 657.784 ns | 0.035 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 524288 | 645.454 ns | 12.7841 ns | 14.2094 ns | 650.756 ns | 0.034 | |
GC.AllocateUninitializedArray | 524288 | 9,936.610 ns | 42.6100 ns | 39.8574 ns | 9,959.137 ns | 0.522 | 0.00 |
'new byte' | 1048576 | 210,343.268 ns | 4,036.2318 ns | 3,775.4937 ns | 209,505.695 ns | 1.000 | |
ArrayPool | 1048576 | 14.407 ns | 0.0054 ns | 0.0045 ns | 14.407 ns | 0.000 | 0.00 |
Marshal.Alloc | 1048576 | 5,664.862 ns | 20.7977 ns | 19.4542 ns | 5,661.308 ns | 0.027 | 0.00 |
'Marshal.Alloc + GCPressure' | 1048576 | 7,513.813 ns | 19.9332 ns | 16.6451 ns | 7,516.030 ns | 0.036 | |
NativeMemory.Alloc | 1048576 | 4,355.013 ns | 8.0762 ns | 7.1594 ns | 4,357.634 ns | 0.021 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 1048576 | 5,020.571 ns | 30.2852 ns | 28.3288 ns | 5,023.151 ns | 0.024 | |
GC.AllocateUninitializedArray | 1048576 | 7,733.933 ns | 129.8119 ns | 121.4262 ns | 7,717.241 ns | 0.037 | 0.00 |
'new byte' | 2097152 | 487,347.627 ns | 61,547.5253 ns | 181,474.2670 ns | 576,913.638 ns | 1.000 | |
ArrayPool | 2097152 | 15.909 ns | 0.0759 ns | 0.0673 ns | 15.882 ns | 0.000 | 0.00 |
Marshal.Alloc | 2097152 | 4,588.926 ns | 35.5412 ns | 33.2452 ns | 4,573.381 ns | 0.010 | 0.01 |
'Marshal.Alloc + GCPressure' | 2097152 | 8,018.549 ns | 47.9033 ns | 42.4650 ns | 8,010.034 ns | 0.018 | |
NativeMemory.Alloc | 2097152 | 4,589.413 ns | 24.3240 ns | 22.7527 ns | 4,588.242 ns | 0.010 | 0.01 |
'NativeMemory.Alloc + GCPressure' | 2097152 | 7,800.359 ns | 24.4334 ns | 21.6596 ns | 7,801.991 ns | 0.018 | |
GC.AllocateUninitializedArray | 2097152 | 16,230.549 ns | 1,001.2648 ns | 2,840.4215 ns | 14,941.833 ns | 0.063 | 0.10 |
'new byte' | 4194304 | 1,153,983.587 ns | 22,865.1377 ns | 34,917.4802 ns | 1,170,402.966 ns | 1.000 | |
ArrayPool | 4194304 | 15.194 ns | 0.0714 ns | 0.0668 ns | 15.204 ns | 0.000 | 0.00 |
Marshal.Alloc | 4194304 | 4,695.135 ns | 49.0898 ns | 45.9186 ns | 4,692.053 ns | 0.004 | 0.00 |
'Marshal.Alloc + GCPressure' | 4194304 | 5,120.850 ns | 14.4461 ns | 12.8061 ns | 5,120.153 ns | 0.004 | |
NativeMemory.Alloc | 4194304 | 7,144.996 ns | 53.5635 ns | 50.1033 ns | 7,139.875 ns | 0.006 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 4194304 | 8,005.085 ns | 74.1182 ns | 65.7039 ns | 8,014.642 ns | 0.007 | |
GC.AllocateUninitializedArray | 4194304 | 56,849.782 ns | 9,976.5391 ns | 28,943.7489 ns | 48,485.974 ns | 0.049 | 0.02 |
'new byte' | 8388608 | 1,148,999.833 ns | 22,853.2166 ns | 40,025.5654 ns | 1,149,472.656 ns | 1.000 | |
ArrayPool | 8388608 | 14.672 ns | 0.1140 ns | 0.1067 ns | 14.654 ns | 0.000 | 0.00 |
Marshal.Alloc | 8388608 | 4,657.386 ns | 34.4025 ns | 32.1801 ns | 4,665.833 ns | 0.004 | 0.00 |
'Marshal.Alloc + GCPressure' | 8388608 | 5,151.209 ns | 38.3535 ns | 35.8759 ns | 5,146.686 ns | 0.005 | |
NativeMemory.Alloc | 8388608 | 7,180.269 ns | 25.9670 ns | 24.2896 ns | 7,178.865 ns | 0.006 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 8388608 | 5,175.859 ns | 34.8045 ns | 32.5561 ns | 5,166.141 ns | 0.005 | |
GC.AllocateUninitializedArray | 8388608 | 582,251.110 ns | 31,505.5869 ns | 92,894.9338 ns | 589,878.369 ns | 0.496 | 0.08 |
'new byte' | 16777216 | 1,835,476.538 ns | 36,402.7929 ns | 102,674.7232 ns | 1,837,862.939 ns | 1.000 | |
ArrayPool | 16777216 | 14.438 ns | 0.0617 ns | 0.0577 ns | 14.430 ns | 0.000 | 0.00 |
Marshal.Alloc | 16777216 | 4,766.127 ns | 28.3081 ns | 26.4794 ns | 4,761.963 ns | 0.002 | 0.00 |
'Marshal.Alloc + GCPressure' | 16777216 | 5,266.717 ns | 37.5639 ns | 35.1373 ns | 5,258.134 ns | 0.003 | |
NativeMemory.Alloc | 16777216 | 7,130.423 ns | 44.2171 ns | 41.3607 ns | 7,136.340 ns | 0.004 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 16777216 | 5,322.742 ns | 17.3828 ns | 13.5714 ns | 5,327.187 ns | 0.003 | |
GC.AllocateUninitializedArray | 16777216 | 1,608,216.958 ns | 47,482.1191 ns | 140,002.0994 ns | 1,607,935.217 ns | 0.881 | 0.09 |
'new byte' | 33554432 | 2,586,667.734 ns | 322,461.3751 ns | 950,784.6401 ns | 2,520,573.242 ns | 1.000 | |
ArrayPool | 33554432 | 17.521 ns | 0.0986 ns | 0.0874 ns | 17.499 ns | 0.000 | 0.00 |
Marshal.Alloc | 33554432 | 7,403.940 ns | 43.5760 ns | 40.7610 ns | 7,395.505 ns | 0.003 | 0.00 |
'Marshal.Alloc + GCPressure' | 33554432 | 5,395.639 ns | 47.5055 ns | 44.4367 ns | 5,401.366 ns | 0.003 | |
NativeMemory.Alloc | 33554432 | 4,674.743 ns | 30.5416 ns | 28.5687 ns | 4,670.855 ns | 0.002 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 33554432 | 5,395.462 ns | 43.5393 ns | 40.7267 ns | 5,394.284 ns | 0.003 | |
GC.AllocateUninitializedArray | 33554432 | 2,179,107.702 ns | 43,172.6520 ns | 100,059.1858 ns | 2,189,359.583 ns | 1.003 | 0.41 |
'new byte' | 67108864 | 2,239,400.302 ns | 139,427.1431 ns | 411,104.0771 ns | 2,200,031.348 ns | 1.000 | |
ArrayPool | 67108864 | 16.233 ns | 0.0554 ns | 0.0491 ns | 16.209 ns | 0.000 | 0.00 |
Marshal.Alloc | 67108864 | 5,134.274 ns | 22.7777 ns | 21.3063 ns | 5,134.368 ns | 0.002 | 0.00 |
'Marshal.Alloc + GCPressure' | 67108864 | 5,696.211 ns | 51.0449 ns | 47.7474 ns | 5,696.205 ns | 0.003 | |
NativeMemory.Alloc | 67108864 | 7,734.205 ns | 50.1103 ns | 44.4215 ns | 7,739.951 ns | 0.004 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 67108864 | 7,179.701 ns | 59.8916 ns | 53.0924 ns | 7,187.198 ns | 0.003 | |
GC.AllocateUninitializedArray | 67108864 | 2,620,094.243 ns | 122,614.2257 ns | 361,530.8110 ns | 2,662,540.283 ns | 1.208 | 0.28 |
'new byte' | 134217728 | 2,807,654.795 ns | 59,852.9969 ns | 174,594.0012 ns | 2,787,194.434 ns | 1.000 | |
ArrayPool | 134217728 | 17.360 ns | 0.0999 ns | 0.0934 ns | 17.349 ns | 0.000 | 0.00 |
Marshal.Alloc | 134217728 | 8,191.272 ns | 35.0218 ns | 31.0459 ns | 8,196.585 ns | 0.003 | 0.00 |
'Marshal.Alloc + GCPressure' | 134217728 | 6,022.638 ns | 96.8344 ns | 90.5789 ns | 6,016.302 ns | 0.002 | |
NativeMemory.Alloc | 134217728 | 5,672.151 ns | 41.0983 ns | 38.4434 ns | 5,676.926 ns | 0.002 | 0.00 |
'NativeMemory.Alloc + GCPressure' | 134217728 | 6,060.486 ns | 35.3757 ns | 31.3597 ns | 6,058.861 ns | 0.002 | |
GC.AllocateUninitializedArray | 134217728 | 2,908,906.631 ns | 57,655.1371 ns | 164,493.3504 ns | 2,924,241.309 ns | 1.040 | 0.09 |