Why is the max size of byte[] 2 GB - 57 B?

Viewed 8692

On my 64-bit machine, this C# code works:

new byte[2L * 1024 * 1024 * 1024 - 57]

but this one throws an OutOfMemoryException:

new byte[2L * 1024 * 1024 * 1024 - 56]

Why?

I understand that the maximum size of a managed object is 2 GB and that the array object I'm creating contains more than the bytes I want. Namely, there is 4 bytes (or 8?) for the syncblock number, 8 bytes for MethodTable reference and 4 bytes for the size of the array. That's 24 bytes including padding, so why can't I allocate an array with 2G - 24 bytes? Is the maximum size really exactly 2 GB? If that's the case, what is the rest of 2 GB used for?

Note: I don't actually need to allocate an array with 2 million of bytes. And even if I did, 56 bytes is negligible overhead. And I could easily work around the limit using custom BigArray<T>.

3 Answers

You can actually find this limit explicitly set and verified in .net source code, and it provides some insight on why this was done (efficient implementation of advanced range check elimination):

https://github.com/dotnet/runtime/blob/b42188a8143f3c7971a7ab1c735e31d8349e7991/src/coreclr/vm/gchelpers.cpp

inline SIZE_T MaxArrayLength()
{
    // Impose limits on maximum array length to prevent corner case integer overflow bugs
    // Keep in sync with Array.MaxArrayLength in BCL.
    return 0X7FFFFFC7;
}
...

if ((SIZE_T)cElements > MaxArrayLength())
    ThrowOutOfMemoryDimensionsExceeded();
Related