Неужели в Дарвине нет mremap?

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

Я вижу, что у наших друзей в мире Linux есть mremap, но я не могу найти такую ​​функцию в заголовках на моем Mac. /Developer/SDKs/MacOSX10.6.sdk/usr/include/sys/mman.h имеет следующее:

  • mmap
  • mprotect
  • msync
  • munlock
  • munmap
  • но нет mremap

man mremap подтверждает мои опасения.

В настоящее время мне нужно munmap и mmmap, если я хочу изменить размер сопоставленного файла, что включает в себя аннулирование всех загруженных страниц. Должен быть лучший способ. Конечно?

Я пытаюсь написать код, который будет работать на Mac OS X и Linux. Я мог бы согласиться на макрос, чтобы использовать лучшую функцию в каждом случае, если бы мне пришлось это сделать, но я бы предпочел сделать это правильно.


person Joe    schedule 19.08.2010    source источник


Ответы (4)


Вы можете обрезать файл до большого размера (создав дыру) и отобразить его целиком. Если файл является постоянным, я рекомендую заполнить дыру вызовами записи, а не записью в сопоставлении, поскольку в противном случае блоки файла могут быть излишне фрагментированы на диске.

person jilles    schedule 19.08.2010
comment
Так вы предлагаете мне выделить максимально возможный размер, который я когда-либо хотел, и заполнить дыру? Это интересная идея, но либо я сопоставляю максимально возможный диапазон адресов и больше не оставляю адресов ни для чего другого, либо использую меньшее количество и рискую закончиться. Кроме того, это не было бы кросс-платформенным (как указано в моем вопросе), поскольку я не мог гарантировать, что какая-то файловая система на самом деле не обнулит весь диапазон файла и не потратит гигабайты. - person Joe; 20.08.2010
comment
Вам даже не нужно делать файл на диске таким большим. Всего на mmap больше размера файла. Доступы за конец файла приведут к SIGBUS, поэтому вам нужно ftruncate дольше, прежде чем пытаться получить доступ к новым частям через mmap, но в остальном все в порядке. - person R.. GitHub STOP HELPING ICE; 25.05.2012
comment
@R..GitHubSTOPHELPINGICE, вы уверены, что это работает на Дарвине? POSIX требует повторного выполнения mmap после увеличения с помощью ftruncate. - person osvein; 18.05.2020
comment
@osvein: О, действительно, не указано, что происходит. Однако MAP_FIXED части, вновь созданной с помощью ftruncate, должна работать. - person R.. GitHub STOP HELPING ICE; 18.05.2020

Если вам нужно уменьшить карту, просто munmap часть в конце, которую вы хотите удалить.

Если вам нужно увеличить карту, вы можете mmap сделать правильное смещение с помощью MAP_FIXED к адресам чуть выше старой карты, но вы должны быть осторожны, чтобы не нанести на карту что-то еще, что уже есть...< /удар>

Приведенный выше текст под зачеркиванием — ужасная идея; MAP_FIXED в корне неверно, если только вы уже не знаете, что находится по целевому адресу, и не хотите атомарно заменить его. Если вы пытаетесь оппортунистически сопоставить что-то новое, если диапазон адресов свободен, вам нужно использовать mmap с запрошенным адресом, но без MAP_FIXED, и посмотреть, удастся ли это и даст ли вам запрошенный адрес; если это удастся, но с другим адресом, вы захотите отменить новое сопоставление, которое вы только что создали, и предположить, что выделение по запрошенному адресу было невозможно.

person R.. GitHub STOP HELPING ICE    schedule 29.12.2010
comment
Не создает ли добавление дополнительного отображаемого региона риск невозможности назначения по этому адресу? - person Joe; 29.12.2010
comment
Да, именно об этом я и предупреждал. Но я считаю, что MAP_FIXED всегда будет отображаться поверх существующего отображения (уничтожая существующее отображение), а не терпеть неудачу, что еще хуже. - person R.. GitHub STOP HELPING ICE; 29.12.2010

Если вы расширяете достаточно большими кусками (скажем, 64 МБ, но это зависит от того, насколько быстро он растет), то стоимость аннулирования старой карты незначительна. Как всегда, проверьте, прежде чем предположить проблему.

person Zan Lynx    schedule 02.04.2011

У меня нет опыта работы с сопоставлением памяти, но похоже, что вы можете временно сопоставить один и тот же файл дважды, чтобы расширить сопоставление, ничего не теряя.

int main() {
    int fd;
    char *fp, *fp2, *pen;

      /* create 1K file */
    fd = open( "mmap_data.txt", O_RDWR | O_CREAT, 0777 );
    lseek( fd, 1000, SEEK_SET );
    write( fd, "a", 1 );

      /* map and populate it */
    fp = mmap( NULL, 1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
    pen = memset( fp, 'x', 1000 );

      /* expand to 8K and establish overlapping mapping */
    lseek( fd, 8000, SEEK_SET );
    write( fd, "b", 1 );
    fp2 = mmap( NULL, 7000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );

      /* demonstrate that mappings alias */
    *fp = 'z';
    printf( "%c ", *fp2 );

      /* eliminate first mapping */
    munmap( fp, 1000 );

      /* populate second mapping */
    pen = memset( fp2+10, 'y', 7000 );

      /* wrap up */
    munmap( fp2, 7000 );
    close( fd );
    printf( "%d\n", errno );
}

Выход zxxxxxxxxxyyyyyy.....

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

person Potatoswatter    schedule 19.08.2010
comment
Поправьте меня, если я ошибаюсь, но не вызовет ли это много дополнительных операций ввода-вывода по сравнению с mmap MAP_PRIVATE и mremap? Из-за сброса MAP_SHARED на диск? - person Eloff; 02.01.2012
comment
@Eloff: Единственный способ - попробовать и посмотреть. Этот пост очень старый, и у меня никогда не было особого стимула проводить эксперимент :vP. Было бы немного удивительно видеть чрезмерные сбросы, поскольку вся память всегда отображается хотя бы один раз. ОС должна сбрасываться только после устранения последнего сопоставления, верно? - person Potatoswatter; 03.01.2012