Почему сборка VS Debug выделяет переменные так далеко друг от друга? - PullRequest
1 голос
/ 26 февраля 2020

Я использую Visual Studio 2019 и заметил, что в отладочных сборках переменные расположены так далеко друг от друга. Я посмотрел на Project Properties и попытался найти в Интернете, но ничего не смог найти. Я запустил следующий код ниже в режимах отладки и выпуска, и вот соответствующие результаты.

int main() {
        int a = 3;
        int b = 5;
        int c = 8;
        int d[5] = { 10,10,10,10,10 };
        int e = 14;

        std::cout << "a: " << &a 
                << "\nb: " << &b
                << "\nc: " << &c 
                << "\nd_start: " << &d[0]
                << "\nd_end: "   << &d[4] + 1
                << "\ne: " << &e 
            << std::endl;
}

Как вы можете видеть ниже, переменные распределяются так, как вы ожидаете (одна за другой) без потерь память между ними. Даже последняя переменная, e, оптимизирована для слота между c и d.

// Release_x64 Build Ouput
a:          0000003893EFFC40
b:          0000003893EFFC44
c:          0000003893EFFC48
d_start:    0000003893EFFC50
d_end:      0000003893EFFC64
e:          0000003893EFFC4C    // e is optimized in between c and d

Ниже приведен вывод, который меня смущает. Здесь вы можете видеть, что a и b расположены на расстоянии 32 байта! Таким образом, между ними находится 28 байт потерянной / неинициализированной памяти. То же самое происходит с другими переменными, за исключением int d[5]. d имеет 32 неинициализированных байта после c, но имеет только 24 неинициализированных байта до e.

// Debug_x64 Build Output
a:          00000086D7EFF3F4
b:          00000086D7EFF414
c:          00000086D7EFF434
d_start:    00000086D7EFF458
d_end:      00000086D7EFF46C
e:          00000086D7EFF484

Мой вопрос таков: почему это происходит? Почему MSV C распределяет эти переменные так далеко друг от друга и что определяет, на сколько места их разделить, чтобы они отличались для массивов?

1 Ответ

0 голосов
/ 27 февраля 2020

Отладочная версия выделяет хранилище не так, как версия выпуска. В частности, отладочная версия выделяет некоторое пространство в начале и конце каждого блока хранилища, поэтому его шаблоны распределения несколько отличаются.

Распределитель отладки также проверяет хранилище в начале и конце блока, в котором он находится. выделено, чтобы увидеть, был ли он поврежден в любом случае

Память выделяется в квантованных блоках, где квант не указан, но имеет размер 16 или 32 байта. Таким образом, если вы выделили массив DWORD из шести элементов (size = 6 * sizeof (DWORD) bytes = 24 bytes), то распределитель фактически доставит 32 байта (один 32-байтовый квант или два 16-байтовых кванта). Поэтому, если вы пишете элемент [6] (седьмой элемент), вы перезаписываете часть «мертвого пространства», и ошибка не обнаруживается. Но в версии выпуска квант может быть 8 байтов, и три 8-байтовых кванта будут выделены, и запись элемента [6] массива перезапишет часть структуры данных распределителя памяти, которая принадлежит следующему фрагменту. После этого все идет под гору. Там ошибка может даже не появиться, пока программа не выйдет! Вы можете построить подобные ситуации "граничного условия" для кванта любого размера. Поскольку квантовый размер одинаков для обеих версий распределителя, но отладочная версия распределителя добавляет скрытое пространство для своих собственных целей, вы получите разные шаблоны распределения хранилища в режиме отладки и выпуска.

...