Среды POSIX предоставляют как минимум два способа доступа к файлам. Там в стандартных системных вызовах open()
, read()
, write()
и друзья, но есть также возможность использования mmap()
для отображения файла в виртуальную память.
Когда предпочтительнее использовать один над другим? В чем заключаются их индивидуальные преимущества, включая два интерфейса?
Ответы:
mmap
замечательно, если у вас есть несколько процессов, обращающихся к данным только для чтения из одного и того же файла, что типично для серверных систем, которые я пишу.mmap
позволяет всем этим процессам совместно использовать одни и те же страницы физической памяти, экономя много памяти.mmap
также позволяет операционной системе оптимизировать операции подкачки. Например, рассмотрим две программы; программа,A
которая читает1MB
файл в буфер, создаваемый с помощьюmalloc
, и программа B, котораяmmaps
хранит файл размером 1 МБ в памяти. Если операционная система должна выгрузить частьA
памяти, она должна записать содержимое буфера для замены, прежде чем она сможет повторно использовать память. В этомB
случае любые немодифицированныеmmap
d-страницы могут быть немедленно использованы повторно, поскольку ОС знает, как восстановить их из существующего файла, из которого они былиmmap
извлечены. (ОС может определить, какие страницы не изменены, изначально пометив доступные для записиmmap
«d» страницы как «только для чтения» и обнаружив ошибки сегмента , аналогично стратегии « Копировать при записи» ).mmap
также полезно для межпроцессного взаимодействия . Вы можетеmmap
сделать файл доступным для чтения / записи в процессах, которые должны взаимодействовать, а затем использовать примитивы синхронизации вmmap'd
регионе (для этого и предназначенMAP_HASSEMAPHORE
флаг).Одно место
mmap
может быть неудобным, если вам нужно работать с очень большими файлами на 32-битной машине. Это потому,mmap
что нужно найти непрерывный блок адресов в адресном пространстве вашего процесса, который достаточно велик, чтобы соответствовать всему диапазону отображаемого файла. Это может стать проблемой, если ваше адресное пространство становится фрагментированным, когда у вас может быть 2 ГБ свободного адресного пространства, но ни один из его отдельных диапазонов не может соответствовать отображению файла 1 ГБ. В этом случае вам, возможно, придется отобразить файл более мелкими порциями, чем вы хотели бы, чтобы он подходил.Другая потенциальная неловкость
mmap
в качестве замены для чтения / записи заключается в том, что вы должны начать отображение на смещениях размера страницы. Если вы просто хотите получить данные со смещением,X
вам нужно исправить это смещение, чтобы оно было совместимо сmmap
.И , наконец, чтение / запись является единственным способом вы можете работать с некоторыми типами файлов.
mmap
не может быть использовано на таких вещах, как трубы и тт .источник
MAP_HASSEMAPHORE
является специфическим для BSD.Одна из областей, где я обнаружил, что mmap () не является преимуществом, была при чтении небольших файлов (до 16K). Затраты на сбой страницы при чтении всего файла были очень высоки по сравнению с простым системным вызовом read (). Это потому, что ядро иногда может полностью удовлетворить чтение в вашем интервале времени, то есть ваш код не переключается. С ошибкой страницы казалось более вероятным, что будет запланирована другая программа, что приведет к более высокой задержке файловой операции.
источник
malloc
часть памяти и делает 1read
в нее. Это позволяет иметь тот же код, который обрабатывает карты памяти, обрабатывает malloc'ed.read
доступа были выше, чем затраты на манипулирование виртуальной памятью.mmap
необходимо обновить 4 записи в таблице страниц. Но использованиеread
для копирования в буфер 16K также включает в себя обновление записей таблицы из 4 страниц, не говоря уже о том, что необходимо скопировать 16K в пространство адресов пользователя. Не могли бы вы рассказать о различиях в операциях с таблицей страниц и о том, как это обходится дорожеmmap
?mmap
имеет преимущество, когда у вас есть произвольный доступ к большим файлам. Еще одним преимуществом является то, что вы обращаетесь к нему с помощью операций с памятью (memcpy, арифметика указателей), не беспокоясь о буферизации. Нормальный ввод-вывод может иногда быть довольно сложным при использовании буферов, когда у вас есть структуры больше, чем ваш буфер. Код для обработки, который часто трудно понять правильно, mmap, как правило, проще. Тем не менее, есть определенные ловушки при работе сmmap
. Как уже упоминалось,mmap
настройка довольно дорогая, поэтому ее стоит использовать только для определенного размера (в зависимости от машины).Для чисто последовательного доступа к файлу это также не всегда лучшее решение, хотя соответствующий вызов
madvise
может смягчить проблему.Вы должны быть осторожны с ограничениями выравнивания вашей архитектуры (SPARC, Itanium), при чтении / записи IO буферы часто правильно выровнены и не перехватываются при разыменовании приведенного указателя.
Вы также должны быть осторожны, чтобы не получить доступ за пределами карты. Это может легко произойти, если вы используете строковые функции на вашей карте, и ваш файл не содержит \ 0 в конце. Он будет работать большую часть времени, когда размер вашего файла не кратен размеру страницы, так как последняя страница заполнена 0 (отображаемая область всегда имеет размер, кратный размеру вашей страницы).
источник
В дополнение к другим приятным ответам, цитата из системного программирования Linux, написанная экспертом Google Робертом Лавом:
источник
Отображение памяти имеет огромное преимущество в скорости по сравнению с традиционным вводом-выводом. Это позволяет операционной системе считывать данные из исходного файла при касании страниц в отображенном файле памяти. Это работает путем создания ошибочных страниц, которые ОС обнаруживает, а затем ОС автоматически загружает соответствующие данные из файла.
Это работает так же, как механизм подкачки, и обычно оптимизируется для высокоскоростного ввода-вывода, считывая данные по границам и размерам системных страниц (обычно 4 КБ) - размер, для которого оптимизируется большинство кешей файловой системы.
источник
pread
. В Solaris 9 Sparc (V890) доступ к pread в 2–3 раза медленнее, чемmemcpy
из mmap. Но вы правы, что последовательный доступ не обязательно быстрее.Преимущество, которого пока нет в списке, это возможность
mmap()
сохранять сопоставление только для чтения как чистые страницы. Если кто-то выделяет буфер в адресном пространстве процесса, а затем использует егоread()
для заполнения буфера из файла, страницы памяти, соответствующие этому буферу, теперь грязные, так как они были записаны.Грязные страницы не могут быть сброшены ядром из оперативной памяти. Если есть место подкачки, то они могут быть выгружены для обмена. Но это дорого, и в некоторых системах, таких как небольшие встроенные устройства с только флэш-памятью, подкачки вообще нет. В этом случае буфер будет зависать в ОЗУ до тех пор, пока процесс не завершится или, возможно, не вернет его обратно
madvise()
.Не написанные на
mmap()
страницах чистые. Если ядру требуется ОЗУ, оно может просто отбросить их и использовать ОЗУ, в котором находились страницы. Если процесс, который имел сопоставление, снова обращается к нему, это вызывает сбой страницы, и ядро перезагружает страницы из файла, из которого они исходно пришли. , Так же, как они были заселены в первую очередь.Для этого не требуется более одного процесса, использующего сопоставленный файл, чтобы иметь преимущество.
источник
read()
страницы, на которые в конечном итоге помещаются данные, не имеют отношения к файлу, с которого они могли прийти. Поэтому их нельзя выписать, кроме как поменять место. Если файл естьmmap()ed
, и сопоставление доступно для записи (в отличие от только для чтения) и записано, то это зависит от того, было ли сопоставлениеMAP_SHARED
илиMAP_PRIVATE
. Совместное отображение может / должно быть записано в файл, но частное не может быть.