Сколько памяти занимают объекты?

306
03 февраля 2018, 22:54

Провел несколько тестов, и был весьма удивлен... Режим компиляции x64. Первый тест показал 4 байта, здесь все нормально. Второй 32. Ого подумал я. И трейтий 32 WTF ???

static int count = 10000000;
        static void Array_C()
    {
        var size = GC.GetTotalMemory(true);
        var arr = new int[count];
        for (var i = 0; i < count; ++i)
        {
            arr[i] = i;
        }
        var mem = GC.GetTotalMemory(true) - size;
        Console.WriteLine("Выделено памяти: " + mem + ", размер одного объекта: " + Math.Truncate((double)mem / count) + ", код последней " + arr.Last());
    }
    static void Array_E()
    {
        var size = GC.GetTotalMemory(true);
        var arr = new object[count];
        for (var i = 0; i < count; ++i)
        {
            arr[i] = new object();
        }
        var mem = GC.GetTotalMemory(true) - size;
        Console.WriteLine("Выделено памяти: " + mem + ", размер одного объекта: " + Math.Truncate((double)mem / count) + ", код последней " + arr.Last().GetHashCode());
    }
    static void Array_F()
    {
        var size = GC.GetTotalMemory(true);
        var arr = new C[count];
        for (var i = 0; i < count; ++i)
        {
            arr[i] = new C { Val0 = i, Val1 = i };
        }
        var mem = GC.GetTotalMemory(false) - size;
        Console.WriteLine("Выделено памяти: " + mem + ", размер одного объекта: " + Math.Truncate((double)mem / count) + ", код последней " + arr.Last().Val0 + arr.Last().Val1);
    }
[StructLayout(LayoutKind.Sequential, Pack = 1)]
class C
{
    public int Val0;
    public int Val1;
}

Вопрос даже не в том почему во втором тесте один экземляр занимает 32 байта. А в том почему в третьем тесте экземпляр не занимает 40 байт.

Answer 1

Во первых, в данном коде неправильно измеряется размер для массива ссылочных типов. Код:

var size = GC.GetTotalMemory(true);
var arr = new object[count];
for (var i = 0; i < count; ++i)
{
        arr[i] = new object();
}
var mem = GC.GetTotalMemory(true) - size;

Измеряет память под массив ссылок + память по объекты. Надо так:

var arr = new object[count];
var size = GC.GetTotalMemory(true);
for (var i = 0; i < count; ++i)
{
        arr[i] = new object();
}
var mem = GC.GetTotalMemory(true) - size;

Во вторых, арифметика Размер C = Размер object + 2 * Размер int не работает: все несколько сложнее.

  1. В CLR существует минимальный размер объекта, см. object.h

    //
    // The generational GC requires that every object be at least 12 bytes
    // in size.   
    #define MIN_OBJECT_SIZE     (2*sizeof(BYTE*) + sizeof(ObjHeader))
    

    Для 64-разрядной версии минимальный размер 2 * 8 + 8 = 24. Размер типа, меньшего 24 байта, дополняется до 24.

    (Определение ObjHeader здесь: https://github.com/dotnet/coreclr/blob/master/src/gc/env/gcenv.object.h)

  2. Размер служебного блока, добавляемого к любому ссылочному типу, равен 16 байт (для x86 - 8 байт, см. например здесь, для x64 в два раза больше).

  3. Кроме того, предположительно, работает дополнение размера до числа, кратного 8.

Таким образом:

Размер объекта с 1 int полем = 24 байта
Размер объекта с 2 int полями = 24 байта
Размер объекта с 3 int полями = 32 байта

READ ALSO
Как прочитать в сервисе значение из реестра?

Как прочитать в сервисе значение из реестра?

Столкнулся с проблемойЕсть WF, в ней есть часть кода по сохранению значения в реестре:

223
C# ищу библиотеки/классы для быстропроизводительного наложения фильтра

C# ищу библиотеки/классы для быстропроизводительного наложения фильтра

Накладываю фильтры на входящее с запросом изображение, а потом отправляю обратно Обрабатываю это всё сейчас с помощью Bitmap, очень удобно,...

239
Вычисление упреждения при стрельбе Unity2D (C#)

Вычисление упреждения при стрельбе Unity2D (C#)

Итак, если вы когда- нибудь играли в космические шутеры, то видели, что для кинетического орудия (или любого другого, чьи пули настигают цель...

275
Вопрос о тестировании класса

Вопрос о тестировании класса

Добрый деньПредположим у меня есть примерно такой класс:

281