Я считаю, что размер заголовка составляет два слова - одно для ссылки на тип, одно для блока синхронизации и другие флаги. Заполнения (я полагаю) достаточно, чтобы округлить общий размер до целого числа слов.
Например, ссылочный тип, содержащий только int, занимает 12 байтов на x86, как показано здесь:
using System;
public class Foo
{
int x;
public Foo(int x)
{
this.x = x;
}
}
public class Test
{
static void Main(string[] args)
{
int length = int.Parse(args[0]);
Foo x = new Foo(0);
Foo[] array = new Foo[length];
// Make sure that JITting the string constructor doesn't
// change things
long start = GC.GetTotalMemory(true);
for (int i=0; i < length; i++)
{
array[i] = new Foo(i);
}
long end = GC.GetTotalMemory(true);
GC.KeepAlive(array);
GC.KeepAlive(x);
decimal totalDecimal = end-start;
Console.WriteLine(totalDecimal / length);
}
}
Один интересный момент - по какой-то причине экземпляр System.Object занимает 12 байтов (на x86) вместо 8, которые я бы иначе предсказал. Как будто минимальный размер составляет 12 байтов, но вы получаете первые четыре байта реальных данных бесплатно:)
Не знаю, почему указанный размер не является целым числом, кстати - я подозреваю, что это связано с небольшим количеством дополнительной памяти, необходимой для каждой страницы в управляемой куче, или с чем-то вроде этого. Иногда результат чуть больше 12, иногда чуть меньше 12 - это, кажется, зависит от указанной длины. (В предыдущей версии этого ответа была ошибка, при которой он анализировал первую аргумент командной строки arg, но затем игнорировал ее. Я исправил это.) В любом случае, я не верю, что эта небольшая неточность имеет какое-либо отношение к размеру отдельного объекта в памяти.