En informática , mmap(2)
es una llamada al sistema Unix compatible con POSIX que asigna archivos o dispositivos a la memoria. Es un método de E/S de archivos asignados a la memoria . Implementa la paginación por demanda porque el contenido de los archivos no se lee inmediatamente desde el disco e inicialmente no utiliza RAM física en absoluto. Las lecturas reales desde el disco se realizan después de que se accede a una ubicación específica, de manera diferida . Una vez que ya no se necesita la asignación, los punteros deben desasignarse con . La información de protección (por ejemplo, marcar regiones asignadas como ejecutables) se puede administrar con , y se puede aplicar un tratamiento especial con . munmap(2)
mprotect(2)
madvise(2)
En Linux , macOS y BSD , mmap
se pueden crear varios tipos de asignaciones. Es posible que otros sistemas operativos solo admitan un subconjunto de ellas; por ejemplo, las asignaciones compartidas pueden no ser prácticas en un sistema operativo sin un VFS global o una caché de E/S.
El diseño original de los archivos mapeados en memoria provino del sistema operativo TOPS-20mmap
y las llamadas de sistemas asociadas se diseñaron como parte de la versión de Unix de Berkeley Software Distribution (BSD). Su API ya estaba descrita en el Manual del sistema 4.2BSD, aunque no se implementó en esa versión ni en 4.3BSD. [1] Sin embargo, Sun Microsystems había implementado esta misma API en su sistema operativo SunOS . Los desarrolladores de BSD en la Universidad de California, Berkeley, solicitaron sin éxito a Sun que donara su implementación; 4.3BSD-Reno se envió en su lugar con una implementación basada en el sistema de memoria virtual de Mach . [2]
La asignación respaldada por archivos asigna un área de la memoria virtual del proceso a archivos; es decir, la lectura de esas áreas de memoria hace que se lea el archivo. Es el tipo de asignación predeterminado.
El mapeo anónimo mapea un área de la memoria virtual del proceso que no está respaldada por ningún archivo y que se pone a disposición a través de los indicadores MAP_ANONYMOUS
/ MAP_ANON
. El contenido se inicializa a cero. [3] En este sentido, un mapeo anónimo es similar a malloc y se utiliza en algunas implementaciones de malloc para ciertas asignaciones, particularmente las grandes.
Si la asignación es compartida (el MAP_SHARED
indicador está establecido), se conserva cuando se bifurca un proceso (mediante una fork(2)
llamada al sistema). Por lo tanto, las escrituras en un área asignada en un proceso son visibles inmediatamente en todos los procesos relacionados (principal, secundario o hermano). Si la asignación es compartida y está respaldada por un archivo (no MAP_ANONYMOUS
), solo se garantiza que el medio de archivo subyacente se escriba después de que se pase a la msync(2)
llamada al sistema. Por el contrario, si la asignación es privada (el MAP_PRIVATE
indicador está establecido), los cambios no serán vistos por otros procesos ni se escribirán en el archivo.
Un proceso que lee o escribe en el archivo subyacente no siempre verá los mismos datos que un proceso diferente que haya mapeado el archivo, ya que los segmentos del archivo se copian en la RAM y solo se vacían periódicamente en el disco. La sincronización se puede forzar con una llamada a msync(2)
.
El uso de mmap en archivos puede reducir significativamente la sobrecarga de memoria para las aplicaciones que acceden al mismo archivo; pueden compartir el área de memoria que abarca el archivo, en lugar de cargar el archivo para cada aplicación que desee acceder a él. Esto significa que mmap(2) se utiliza a veces para la comunicación entre procesos (IPC). En los sistemas operativos modernos , mmap(2 se prefiere normalmente a la función de memoria compartida IPC de System V. [4]
La principal diferencia entre la memoria compartida del Sistema V (shmem) y la E/S mapeada en memoria (mmap) es que la memoria compartida del Sistema V es persistente: a menos que un proceso la elimine explícitamente, se mantiene en la memoria y permanece disponible hasta que se apaga el sistema. La memoria mapeada en memoria no es persistente entre ejecuciones de aplicaciones (a menos que esté respaldada por un archivo).
#include <sys/types.h> #include <sys/mman.h> #incluir <err.h> #incluir <fcntl.h> #incluir <stdio.h> #incluir <stdlib.h> #include <cadena.h> #include <unistd.h> /* Este ejemplo muestra cómo un mmap de /dev/zero es equivalente a utilizando memoria anónima (MAP_ANON) no conectada a ningún archivo. NB MAP_ANONYMOUS o MAP_ANON son compatibles con la mayoría de UNIX versiones, eliminando el propósito original de /dev/zero.*//* No funciona en OS X o macOS, donde no se puede realizar mmap sobre /dev/zero */int principal ( vacío ) { const char str1 [] = "cadena 1" ; const char str2 [] = "cadena 2" ; pid_t parpid = getpid (), childpid ; int fd = -1 ; char * anon , * cero ; si (( fd = abierto ( "/dev/cero" , O_RDWR , 0 )) == -1 ) err ( 1 , "abierto" ); anon = ( char * ) mmap ( NULL , 4096 , PROT_READ | PROT_WRITE , MAP_ANON | MAP_SHARED , -1 , 0 ); cero = ( char * ) mmap ( NULL , 4096 , PROT_READ | PROT_WRITE , MAP_SHARED , fd , 0 ); si ( anónimo == MAP_FAILED || cero == MAP_FAILED ) errx ( 1 , "o mmap" ); strcpy ( anónimo , str1 ); strcpy ( cero , str1 ); printf ( "PID %d: \t anónimo %s, respaldo cero %s \n " , parpid , anon , cero ); cambiar (( childpid = fork ())) { caso -1 : err ( 1 , "bifurcación" ); /* NO ALCANZADO */ caso 0 : childpid = getpid (); printf ( "PID %d: \t anónimo %s, respaldo cero %s \n " , childpid , anon , cero ); dormir ( 3 ); printf ( "PID %d: \t anónimo %s, respaldo cero %s \n " , childpid , anon , cero ); munmap ( anónimo , 4096 ); munmap ( cero , 4096 ); cerrar ( fd ); devolver SALIDA_ÉXITO ; } dormir ( 2 ); strcpy ( anónimo , str2 ); strcpy ( cero , str2 ); printf ( "PID %d: \t anónimo %s, respaldo cero %s \n " , parpid , anon , cero ); munmap ( anónimo , 4096 ); munmap ( cero , 4096 ); cerrar ( fd ); devolver SALIDA_ÉXITO ; }
Ejemplo de salida:
PID 22475: cadena anónima 1, cadena respaldada por cero 1PID 22476: cadena anónima 1, cadena respaldada por cero 1PID 22475: cadena anónima 2, cadena 2 con respaldo ceroPID 22476: cadena anónima 2, cadena 2 con respaldo cero
La llamada al sistema mmap se ha utilizado en varias implementaciones de bases de datos como una alternativa para implementar un grupo de búferes, aunque esto creó un conjunto diferente de problemas que, de manera realista, solo podrían solucionarse utilizando un grupo de búferes. [5]