Нулевое отображение большой памяти с помощью " madvise`
у меня следующая проблема:
Я выделяю большой кусок памяти (несколько GiB) через mmap
С MAP_ANONYMOUS
. Этот кусок содержит большую хэш-карту, которая должна быть обнулена время от времени. Не все отображение может использоваться в каждом раунде (не каждая страница ошибается), поэтому memset
- это не очень хорошая идея - слишком долго.
какова лучшая стратегия, чтобы сделать это быстро?
будет
madvise(ptr, length, MADV_DONTNEED);
мне гарантировать, что любые последующие доступы предоставляют новые пустые страницы?
из Linux man madvise
страницы:
этот вызов не влияет на семантику программы (за исключением MADV_DONTNEED), но может повлиять на его производительность. Ядро свободно игнорировать советы.
...
MADV_DONTNEED
последующие обращения к страницам в этом диапазоне будут успешными, но приведут либо к перезагрузке содержимое памяти из базового сопоставленного файла (см. mmap (2)) или страницы с нулевым заполнением по требованию для сопоставлений без базового файла.
...
текущая реализация Linux (2.4.0) рассматривает этот системный вызов больше как команду, чем как Совет ...
или я должен munmap
и переделать регион заново?
он должен работать на Linux и в идеале иметь такое же поведение на OS X.
3 ответов
существует гораздо более простое решение вашей проблемы, которое довольно портативно:
mmap(ptr, length, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
С MAP_FIXED
разрешено терпеть неудачу по довольно произвольным причинам, связанным с реализацией, возвращаясь к memset
если он возвращает MAP_FAILED
было бы неплохо.
этой madvise
поведение, безусловно, не является стандартным, поэтому это не будет портативным.
если часть, которую вы хотите обнулить, находится в конце вашего отображения, вам может сойти с рук ftruncate
. Вам придется ввести еще один шаг:
-
shm_open
чтобы иметь "постоянный" файловый дескриптор для ваших данных -
ftruncate
в размере -
mmap
этого FD
тогда вы могли бы всегда
munmap
-
ftruncate
к чему-то короткому -
ftruncate
до реальной длины вам нужно -
mmap
снова
и тогда часть, которую вы "переназначили", будет инициализирована нулем.
но имейте в виду, что система должна выполнять обнуление страниц. Это может быть немного эффективнее, чем встроенный материал, который ваш компилятор производит для memset
, но это не обязательно.
в Linux вы можете положиться на MADV_DONTNEED
на анонимном отображении, обнуляющем отображение. Это не портативный, хотя - madvise()
сам по себе не стандартизирован. posix_madvise()
стандартизован, но POSIX_MADV_DONTNEED
тут не имеют то же поведение, что и Linux MADV_DONTNEED
флаг - posix_madvise()
всегда является консультативным и не влияет на семантику приложения.