В вычислительной технике — mmap(2)
это системный вызов Unix, совместимый с POSIX , который отображает файлы или устройства в память. Это метод ввода-вывода файлов, отображаемых в память . Он реализует подкачку по требованию , поскольку содержимое файла не считывается с диска немедленно и изначально вообще не использует физическую оперативную память. Фактические чтения с диска выполняются после доступа к определенному месту, ленивым образом . После того, как отображение больше не требуется, указатели должны быть отменены с помощью . Информацией о защите , например, маркировкой отображенных областей как исполняемых, можно управлять с помощью , а специальную обработку можно применять с помощью . munmap(2)
mprotect(2)
madvise(2)
В Linux , macOS и BSDmmap
можно создавать несколько типов отображений. Другие операционные системы могут поддерживать только подмножество из них; например, общие отображения могут быть непрактичны в операционной системе без глобального VFS или кэша ввода -вывода.
Первоначальный дизайн отображаемых в память файлов пришел из операционной системы TOPS-20 . mmap
и связанные системные вызовы были разработаны как часть версии Berkeley Software Distribution (BSD) Unix. Их API уже был описан в 4.2BSD System Manual, хотя он не был реализован ни в этой версии, ни в 4.3BSD. [1] Однако Sun Microsystems реализовала этот самый API в своей операционной системе SunOS . Разработчики BSD в Калифорнийском университете в Беркли безуспешно просили Sun пожертвовать его реализацию; вместо этого 4.3BSD-Reno была поставлена с реализацией, основанной на системе виртуальной памяти Mach . [2]
Файловое отображение отображает область виртуальной памяти процесса в файлы; то есть чтение этих областей памяти приводит к чтению файла. Это тип отображения по умолчанию.
Анонимное отображение отображает область виртуальной памяти процесса, не подкрепленную каким-либо файлом. Содержимое инициализируется нулем. [3] В этом отношении анонимное отображение похоже на malloc и используется в некоторых реализациях malloc для определенных выделений, особенно больших. Анонимные отображения не являются частью стандарта POSIX, но реализованы почти во всех операционных системах с помощью флагов MAP_ANONYMOUS
и MAP_ANON
.
Если отображение является общим ( MAP_SHARED
установлен флаг), то оно сохраняется при разветвлении процесса (с использованием fork(2)
системного вызова). Таким образом, записи в отображенную область в одном процессе немедленно видны во всех связанных (родительских, дочерних или родственных) процессах. Если отображение является общим и поддерживается файлом (не MAP_ANONYMOUS
), то базовый файловый носитель гарантированно будет записан только после того, как он будет передан системному msync(2)
вызову. Напротив, если отображение является частным ( MAP_PRIVATE
установлен флаг), изменения не будут видны другим процессам и не будут записаны в файл.
Процесс чтения или записи в базовый файл не всегда будет видеть те же данные, что и другой процесс, который сопоставил файл, поскольку сегменты файла копируются в оперативную память и только периодически сбрасываются на диск. Синхронизация может быть принудительно выполнена с помощью вызова msync(2)
.
Использование mmap для файлов может значительно сократить накладные расходы памяти для приложений, получающих доступ к одному и тому же файлу; они могут совместно использовать область памяти, охватываемую файлом, вместо того, чтобы загружать файл для каждого приложения, которое хочет получить к нему доступ. Это означает, что mmap(2) иногда используется для межпроцессного взаимодействия (IPC). В современных операционных системах mmap(2) обычно предпочтительнее, чем System V IPC Shared Memory . [4]
Основное различие между общей памятью System V (shmem) и отображенным в память вводом-выводом (mmap) заключается в том, что общая память System V является постоянной: если она явно не удалена процессом, она сохраняется в памяти и остается доступной до тех пор, пока система не будет выключена. Память mmap не является постоянной между запусками приложений (если она не поддерживается файлом).
#include <sys/types.h> #include <sys/mman.h> #include <err.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <строка.h> #include <unistd.h> /* Этот пример показывает, как mmap /dev/zero эквивалентен использование анонимной памяти (MAP_ANON), не связанной ни с одним файлом. Примечание: MAP_ANONYMOUS или MAP_ANON поддерживаются большинством UNIX-систем. версии, удаляющие первоначальное назначение /dev/zero.*//* Не работает на OS X или macOS, где нельзя выполнить mmap через /dev/zero */int main ( пустота ) { const char str1 [] = "строка 1" ; const char str2 [] = "строка 2" ; pid_t parpid = getpid (), childpid ; int fd = -1 ; char * anon , * ноль ; если (( fd = открыть ( "/dev/zero" , O_RDWR , 0 )) == -1 ) ошибка ( 1 , "открыто" ); anon = ( char * ) mmap ( NULL , 4096 , PROT_READ | PROT_WRITE , MAP_ANON | MAP_SHARED , -1 , 0 ); ноль = ( char * ) mmap ( NULL , 4096 , PROT_READ | PROT_WRITE , MAP_SHARED , fd , 0 ); если ( анон == MAP_FAILED || ноль == MAP_FAILED ) errx ( 1 , "либо mmap" ); strcpy ( анон , str1 ); strcpy ( ноль , str1 ); printf ( "PID %d: \t анонимный %s, с нулевой поддержкой %s \n " , parpid , anon , zero ); переключатель (( childpid = fork ())) { случай -1 : err ( 1 , "вилка" ); /* НЕДОСТИГНУТО */ случай 0 : childpid = getpid (); printf ( "PID %d: \t анонимный %s, с нулевой поддержкой %s \n " , childpid , anon , zero ); сон ( 3 ); printf ( "PID %d: \t анонимный %s, с нулевой поддержкой %s \n " , childpid , anon , zero ); munmap ( аноним , 4096 ); munmap ( ноль , 4096 ); закрыть ( fd ); вернуть EXIT_SUCCESS ; } сон ( 2 ); strcpy ( анон , str2 ); strcpy ( ноль , str2 ); printf ( "PID %d: \t анонимный %s, с нулевой поддержкой %s \n " , parpid , anon , zero ); munmap ( аноним , 4096 ); munmap ( ноль , 4096 ); закрыть ( fd ); вернуть EXIT_SUCCESS ; }
пример вывода:
PID 22475: анонимная строка 1, строка с нулевой поддержкой 1PID 22476: анонимная строка 1, строка с нулевой поддержкой 1PID 22475: анонимная строка 2, строка с нулевой поддержкой 2PID 22476: анонимная строка 2, строка с нулевой поддержкой 2
Системный вызов mmap использовался в различных реализациях баз данных в качестве альтернативы реализации буферного пула, хотя это создавало другой набор проблем, которые можно было реально решить только с помощью буферного пула. [5]