Вам нужно 56 байтов служебных данных.Это на самом деле 2 147 483 649-1 минус 56 для максимального размера.Вот почему ваш минус 57 работает, а минус 56 - нет.
Как Джон Скит говорит здесь:
Однако на практике я не верю, что какая-либо реализация поддерживает такие огромные массивы.CLR имеет ограничение для каждого объекта чуть более 2 ГБ, поэтому даже байтовый массив не может иметь 2147483648 элементов.Немного экспериментов показывает, что на моем компьютере самый большой массив, который вы можете создать, это новый байт [2147483591].(Это на 64-битной .NET CLR; версия Mono, на которой у меня установлены дроссели.)
См. Также эту статью InformIT на ту же тему.Он предоставляет следующий код для демонстрации максимальных размеров и накладных расходов:
class Program
{
static void Main(string[] args)
{
AllocateMaxSize<byte>();
AllocateMaxSize<short>();
AllocateMaxSize<int>();
AllocateMaxSize<long>();
AllocateMaxSize<object>();
}
const long twogigLimit = ((long)2 * 1024 * 1024 * 1024) - 1;
static void AllocateMaxSize<T>()
{
int twogig = (int)twogigLimit;
int num;
Type tt = typeof(T);
if (tt.IsValueType)
{
num = twogig / Marshal.SizeOf(typeof(T));
}
else
{
num = twogig / IntPtr.Size;
}
T[] buff;
bool success = false;
do
{
try
{
buff = new T[num];
success = true;
}
catch (OutOfMemoryException)
{
--num;
}
} while (!success);
Console.WriteLine("Maximum size of {0}[] is {1:N0} items.", typeof(T).ToString(), num);
}
}
Наконец, в статье есть следующее:
Если вы выполните математику, вы увидитечто накладные расходы на выделение массива составляют 56 байтов.В конце осталось несколько байтов из-за размеров объекта.Например, 268 435 448 64-разрядных чисел занимают 2 147 483 584 байта.Добавление заголовка массива 56 байтов дает вам 2 147 483 640, оставляя вам на 7 байтов меньше 2 гигабайт.
Редактировать:
Но подождите, это еще не все!*
Осмотревшись вокруг и поговорив с Джоном Скитом, он указал мне на статью, которую он написал на О памяти и строках .В этой статье он приводит таблицу размеров:
Type x86 size x64 size
object 12 24
object[] 16 + length * 4 32 + length * 8
int[] 12 + length * 4 28 + length * 4
byte[] 12 + length 24 + length
string 14 + length * 2 26 + length * 2
Мр.Скит продолжает:
Вам может быть прощено смотреть на числа выше и думать, что "накладные расходы" объекта составляют 12 байтов в x86 и 24 в x64 ... но это не такСовершенно верно.
и это:
"Базовые" издержки 8 байтов на объект в x86 и 16 на объект в x64... учитывая, что мы можем хранить Int32 «реальных» данных в x86 и по-прежнему иметь размер объекта 12, а также мы можем хранить два Int32 реальных данных в x64 и при этом иметь объект x64.
Существует «минимальный» размер 12 байтов и 24 байта соответственно.Другими словами, вы не можете иметь тип, который является просто накладными расходами.Обратите внимание, что класс «Empty» принимает тот же размер, что и при создании экземпляров Object ... фактически есть некоторая свободная комната, потому что CLR не любит работать с объектом без данных.(Обратите внимание, что структура без полей также занимает место, даже для локальных переменных.)
Объекты x86 дополняются до 4-байтовых границ;на x64 это 8 байтов (как и прежде)
и, наконец, Джон Скит ответил на вопрос, который я ему задал в другом вопросе, где он заявляет (в ответ на статью InformIT , которую я ему показал):
Похоже, статья, на которую вы ссылаетесь, выводит накладные расходы только из предела, равного глупо IMO.
Итак, чтобы ответить на ваш вопрос, фактические накладные расходы составляют 24 байта с 32 байтами свободного места, из того, что я собираю.