Los entornos POSIX proporcionan al menos dos formas de acceder a los archivos. Ahí está el estándar de llamadas al sistema open()
, read()
, write()
, y amigos, pero también existe la opción de usar mmap()
para mapear el archivo en la memoria virtual.
¿Cuándo es preferible usar uno sobre el otro? ¿Cuáles son sus ventajas individuales que merecen incluir dos interfaces?
Respuestas:
mmap
es excelente si tiene múltiples procesos que acceden a los datos en forma de solo lectura desde el mismo archivo, lo cual es común en el tipo de sistemas de servidor que escribo.mmap
permite que todos esos procesos compartan las mismas páginas de memoria física, ahorrando mucha memoria.mmap
También permite que el sistema operativo optimice las operaciones de paginación. Por ejemplo, considere dos programas; programaA
que lee en un1MB
archivo en un búfer creando conmalloc
, y programa B quemmaps
el archivo de 1 MB en la memoria. Si el sistema operativo tiene que intercambiar parte deA
la memoria, debe escribir el contenido del búfer para intercambiar antes de que pueda reutilizar la memoria. EnB
el caso, cualquier páginammap
'd' no modificada se puede reutilizar de inmediato porque el sistema operativo sabe cómo restaurarla desde el archivo existente del quemmap
provino. (El sistema operativo puede detectar qué páginas no se modifican marcando inicialmentemmap
las páginas 'd' editables como de solo lectura y detectando fallas seg , similar a la estrategia Copiar en escritura ).mmap
También es útil para la comunicación entre procesos . Puedemmap
crear un archivo como lectura / escritura en los procesos que necesitan comunicarse y luego usar primitivas de sincronización en lammap'd
región (para eso está laMAP_HASSEMAPHORE
bandera).Un lugar
mmap
puede ser incómodo si necesita trabajar con archivos muy grandes en una máquina de 32 bits. Esto se debe a quemmap
tiene que encontrar un bloque contiguo de direcciones en el espacio de direcciones de su proceso que sea lo suficientemente grande como para adaptarse al rango completo del archivo que se está mapeando. Esto puede convertirse en un problema si su espacio de direcciones se fragmenta, donde puede tener 2 GB de espacio de direcciones libre, pero ningún rango individual puede caber en una asignación de archivos de 1 GB. En este caso, es posible que deba asignar el archivo en fragmentos más pequeños de los que desea para que encaje.Otra posible incomodidad
mmap
como reemplazo de lectura / escritura es que debe comenzar su mapeo en los desplazamientos del tamaño de página. Si solo desea obtener algunos datos en el desplazamientoX
, necesitará corregir ese desplazamiento para que sea compatiblemmap
.Y, por último, leer / escribir son la única forma en que puede trabajar con algunos tipos de archivos.
mmap
no se puede usar en cosas como tuberías y ttys .fuente
MAP_HASSEMAPHORE
es específico de BSD.Un área donde encontré que mmap () no era una ventaja era cuando leía archivos pequeños (menos de 16K). La sobrecarga de la página que no pudo leer el archivo completo fue muy alta en comparación con solo hacer una sola llamada al sistema read (). Esto se debe a que el núcleo a veces puede satisfacer una lectura por completo en su segmento de tiempo, lo que significa que su código no cambia. Con un error de página, parecía más probable que se programara otro programa, lo que hace que la operación del archivo tenga una latencia más alta.
fuente
malloc
un trozo de memoria y convertir 1read
en él. Esto permite tener el mismo código que maneja los mapas de memoria manejar malloc'ed.read
accesos sea mayor que la sobrecarga de la manipulación de la memoria virtual.mmap
tiene que actualizar 4 entradas en la tabla de páginas. Pero usarread
para copiar en un búfer de 16K también implica actualizar las entradas de la tabla de 4 páginas, sin mencionar que necesita copiar el 16K en el espacio de dirección del usuario. Entonces, ¿podría explicar las diferencias de operaciones en la tabla de páginas y cómo es más costosommap
?mmap
tiene la ventaja cuando tiene acceso aleatorio en archivos grandes. Otra ventaja es que accede a él con operaciones de memoria (memcpy, aritmética de puntero), sin molestarse con el almacenamiento en búfer. La E / S normal a veces puede ser bastante difícil cuando se usan buffers cuando tienes estructuras más grandes que tu buffer. El código para manejar que a menudo es difícil de corregir, mmap es generalmente más fácil. Dicho esto, hay ciertas trampas cuando se trabaja conmmap
. Como la gente ya ha mencionado,mmap
es bastante costoso configurarlo, por lo que vale la pena usarlo solo para un tamaño determinado (que varía de una máquina a otra).Para los accesos secuenciales puros al archivo, tampoco es siempre la mejor solución, aunque una llamada adecuada
madvise
puede mitigar el problema.Debe tener cuidado con las restricciones de alineación de su arquitectura (SPARC, itanium), con IO de lectura / escritura, los buffers a menudo están correctamente alineados y no se atrapan al desreferenciar un puntero fundido.
También debe tener cuidado de no acceder fuera del mapa. Puede suceder fácilmente si usa funciones de cadena en su mapa, y su archivo no contiene un \ 0 al final. Funcionará la mayor parte del tiempo cuando el tamaño de su archivo no sea un múltiplo del tamaño de la página, ya que la última página se llena con 0 (el área asignada siempre tiene el tamaño de un múltiplo del tamaño de su página).
fuente
Además de otras buenas respuestas, una cita de la programación del sistema Linux escrita por el experto de Google Robert Love:
fuente
El mapeo de memoria tiene el potencial de una gran ventaja de velocidad en comparación con las E / S tradicionales. Permite que el sistema operativo lea los datos del archivo fuente a medida que se tocan las páginas en el archivo mapeado de memoria. Esto funciona creando páginas con fallas, que el sistema operativo detecta y luego el sistema operativo carga automáticamente los datos correspondientes del archivo.
Esto funciona de la misma manera que el mecanismo de paginación y, por lo general, está optimizado para E / S de alta velocidad mediante la lectura de datos sobre los límites y tamaños de las páginas del sistema (generalmente 4K), un tamaño para el que se optimizan la mayoría de las memorias caché del sistema de archivos.
fuente
pread
. En Solaris 9 Sparc (V890), el acceso de lectura previa es entre 2 y 3 veces más lento que elmemcpy
del mmap. Pero tiene razón en que el acceso secuencial no es necesariamente más rápido.Una ventaja que aún no figura en la lista es la capacidad de
mmap()
mantener una asignación de solo lectura como páginas limpias . Si se asigna un búfer en el espacio de direcciones del proceso, luego se usaread()
para llenar el búfer desde un archivo, las páginas de memoria correspondientes a ese búfer ahora están sucias desde que se escribieron.El kernel no puede quitar páginas sucias de la RAM. Si hay espacio de intercambio, entonces se pueden localizar para intercambiar. Pero esto es costoso y en algunos sistemas, como pequeños dispositivos integrados con solo memoria flash, no hay intercambio en absoluto. En ese caso, el búfer estará atascado en la RAM hasta que el proceso salga, o tal vez lo devuelva
madvise()
.No escrito en las
mmap()
páginas están limpias. Si el kernel necesita RAM, simplemente puede soltarlos y usar la RAM en la que se encontraban las páginas. Si el proceso que tenía el mapeo accede de nuevo, causa un error de página, el kernel vuelve a cargar las páginas del archivo original. . De la misma manera que se poblaron en primer lugar.Esto no requiere más de un proceso usando el archivo mapeado para ser una ventaja.
fuente
read()
, las páginas en las que se colocan los datos finalmente no tienen relación con el archivo del que provienen. Por lo tanto, no se pueden escribir, excepto para intercambiar espacio. Si un archivo esmmap()ed
, y el mapeo es grabable (en lugar de solo lectura), y escrito, entonces depende de si el mapeo fueMAP_SHARED
o noMAP_PRIVATE
. Un mapeo compartido puede / debe escribirse en el archivo, pero un privado no puede ser.