Я пытаюсь выделить и использовать 100 МБ данных (size_t s = 100 * 1024 * 1024
) и измерил различными способами в C ++:
Необработанное выделение без init:
// < 0.01 ms
auto p = new char[s];
C ++ ноль-init:
// 20 ms
auto p = new char[s]();
Ручной ноль-init:
// 20 ms
auto p = new char[s];
for (auto i = 0; i < s; ++i)
p[i] = 0;
Это не ограничение моей памяти, о чем свидетельствует повторная запись памяти:
// 3 ms
std::memset(p, 0xFF, s);
Я также пробовал std::malloc
и std::calloc
, но они показывают то же самое поведение.calloc
возвращает память с нулевой инициализацией, но если я потом сделаю memset
, это все равно займет 20 мс.
Насколько я понимаю, неинициализированная память быстро выделяется, потому что она на самом деле не касаетсяобъем памяти.Только когда я получаю к нему доступ, страницы выделяются для моей программы.3 мс для установки 100 МБ соответствуют ~ 35 ГБ / с, что нормально.Кажется, что 20 мс являются издержками при возникновении ошибок страницы.
Самое смешное, что это, похоже, накладные расходы на вычисления.Если я инициализирую его несколькими потоками, он становится быстрее:
// 6-10 ms
auto p = new char[s];
#pragma omp parallel for
for (auto i = 0; i < s; ++i)
p[i] = 0;
Мой вопрос: есть ли способ не только распределить память, но и сразу же распределить все страницы, чтобы при обращении к ней не возникало дальнейших сбоев страниц?
Я хотел бы по возможности избегать использования огромных страниц.
(Измерение с std::chrono::high_resolution_clock
)
Это было сделано на моей настольной системе (5 ГГц i9, 3600 МГц DDR4)., Linux Mint 19, ядро 4.15.0-45-generic) с Clang 7 (-O2 -march=native
), хотя, глядя на сборку, проблема не в компиляторе.
EDIT: Это упрощенный пример,в моем реальном приложении мне нужно инициализировать его значением, отличным от 0, но это не меняет времени вообще.