Динамическое выделение памяти кажется мгновенным в режиме отладки, но постепенным в режиме выпуска.

У меня есть большой динамически распределяемый массив (C++, MSVC110), и я инициализирую его следующим образом:

try {
    size_t arrayLength = 1 << 28;
    data = new int[arrayLength];
    for (size_t i = 0; i < arrayLength; ++i) {
        data[i] = rand();
    }
}
catch (std::bad_alloc&) { /* Report error. */ }

Все было хорошо, прежде чем я попытался выделить больше, чем фактическая оперативная память системы, например 10 ГБ. Я ожидал поймать исключение bad_alloc, но система (Win7) начала меняться как сумасшедшая и т. д., вы знаете, о чем я говорю.

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

Режим отладки:

График распределения режима отладки

Режим выпуска:

График распределения режима выпуска

Что вызывает это? Может ли это негативно сказаться на производительности? Я сделал что-то не так? Является ли причиной этого ОС? Или распределитель С++?

На самом деле я бы предпочел получить исключение, если памяти недостаточно, а не переходить к бесконечному циклу подкачки. Есть ли способ добиться этого на С++?

Я знаю, что одним из решений может быть отключение подкачки в Windows, но это решит проблему только для меня.


person NightElfik    schedule 28.01.2014    source источник
comment
Я думаю, это вызвано тем, что код библиотеки DEBUG C-standard помещает определенную отладочную информацию в любую выделенную память, тем самым немедленно получая к ней доступ и вызывая ее выгрузку. В выпуске вы, вероятно, постепенно загружаете память, в зависимости от того, как вы к ней обращаетесь/используете.   -  person MicroVirus    schedule 28.01.2014
comment
Я согласен с MicroVirus. Проверьте это article для получения дополнительной информации о метаданных кучи отладки Windows.   -  person Manu343726    schedule 28.01.2014
comment
@MicroVirus, пожалуйста, напишите свой ответ   -  person imreal    schedule 29.01.2014


Ответы (1)


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

В режиме деблокирования именно ваш код выполняет линейное заполнение блока, таким образом фиксируя одну страницу за раз.

Что касается ограничения объема памяти, у вас есть системные вызовы, чтобы сообщить вам о доступных ресурсах. Это, например, в Windows среда.

Сбой системного вызова, если требуется пила памяти, не имеет смысла, поскольку объем доступной памяти постоянно изменяется из-за обстоятельств, которые данная программа не может контролировать (например, запуск других приложений).

Есть возможность сделать некоторые блоки памяти не подкачиваемыми (т. е. заблокированными в ОЗУ), но такое использование обычно ограничивается системными уровнями, такими как драйверы.

Вы сами определяете доступную память и устанавливаете ограничение на ее выделение.

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

Если подкачка является убийцей для вашего приложения, вам следует подумать о запасе прочности (т.е. попытаться оставить что-то вроде 500 МБ или 1 ГБ ОЗУ доступным для системы)

person kuroi neko    schedule 28.01.2014
comment
Я считаю, что новый блок памяти заполнен 0xCDCDCDCD, чтобы показать, что это неинициализированная память кучи. - person drescherjm; 29.01.2014
comment
stackoverflow.com/questions/127386/ - person drescherjm; 29.01.2014
comment
@drescherjm Да, но перед этим я подозреваю, что распределитель выполняет другие обращения, иначе вы должны увидеть тот же результат, что и в версии выпуска. - person kuroi neko; 29.01.2014
comment
Релиз не заполняет кучу. - person drescherjm; 29.01.2014
comment
@drescherjm Да, но пример ОП делает - person kuroi neko; 29.01.2014
comment
Понятно.. Извините за шум. - person drescherjm; 29.01.2014
comment
@drescherjm Нет проблем. Ваши пункты действительны, и разъяснение приветствуется. - person kuroi neko; 29.01.2014
comment
Единственное, что меня удивляет, так это то, что отладочная версия может так быстро заполнять память, а мой код намного медленнее. Возможно, генератор случайных чисел (std::mt199370 замедляет работу. Кроме того, я обращаюсь к памяти с помощью символов, поэтому это еще больше замедляет итерацию. - person NightElfik; 29.01.2014