Нулевое отображение большой памяти с помощью " 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. Вам придется ввести еще один шаг:

  1. shm_open чтобы иметь "постоянный" файловый дескриптор для ваших данных
  2. ftruncate в размере
  3. mmap этого FD

тогда вы могли бы всегда

  1. munmap
  2. ftruncate к чему-то короткому
  3. ftruncate до реальной длины вам нужно
  4. mmap снова

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

но имейте в виду, что система должна выполнять обнуление страниц. Это может быть немного эффективнее, чем встроенный материал, который ваш компилятор производит для memset, но это не обязательно.


в Linux вы можете положиться на MADV_DONTNEED на анонимном отображении, обнуляющем отображение. Это не портативный, хотя - madvise() сам по себе не стандартизирован. posix_madvise() стандартизован, но POSIX_MADV_DONTNEED тут не имеют то же поведение, что и Linux MADV_DONTNEED флаг - posix_madvise() всегда является консультативным и не влияет на семантику приложения.