¿Cuáles son las ventajas de los archivos asignados en memoria?

89

He estado investigando archivos mapeados en memoria para un proyecto y agradecería cualquier pensamiento de personas que los hayan usado antes o hayan decidido no usarlos, y ¿por qué?

En particular, me preocupa lo siguiente, en orden de importancia:

  • concurrencia
  • acceso aleatorio
  • actuación
  • facilidad de uso
  • portabilidad
robottobor
fuente

Respuestas:

56

Creo que la ventaja es realmente que reduce la cantidad de copia de datos requerida sobre los métodos tradicionales de lectura de un archivo.

Si su aplicación puede usar los datos "en su lugar" en un archivo mapeado en memoria, puede ingresar sin ser copiado; si usa una llamada al sistema (por ejemplo, pread () de Linux), entonces normalmente implica que el núcleo copie los datos de sus propios búferes en el espacio de usuario. Esta copia adicional no solo lleva tiempo, sino que disminuye la efectividad de las cachés de la CPU al acceder a esta copia adicional de los datos.

Si los datos realmente tienen que leerse desde el disco (como en E / S físicas), entonces el sistema operativo aún tiene que leerlos, una falla de página probablemente no sea mejor en cuanto a rendimiento que una llamada al sistema, pero si no lo haga (es decir, ya está en la caché del sistema operativo), el rendimiento debería, en teoría, ser mucho mejor.

En el lado negativo, no hay una interfaz asincrónica para los archivos asignados en memoria: si intenta acceder a una página que no está asignada, genera una falla de página y luego hace que el hilo espere la E / S.


La desventaja obvia de los archivos asignados en memoria está en un sistema operativo de 32 bits: puede quedarse sin espacio de direcciones fácilmente.

MarkR
fuente
4
En Windows, al menos puede mapear múltiples vistas de 32 bits de un archivo mmap más grande, lo que puede ser más eficiente que tratar de tratar con archivos muy grandes usando la función CRT regular
Martin Beckett
@MarkR Escribió que "su copia adicional no solo lleva tiempo, sino que disminuye la efectividad de los cachés de la CPU al acceder a esta copia adicional de los datos ". ( énfasis mío). ¿Puede explicar cómo la copia de búfer adicional en el kernel dificulta la efectividad de las cachés de la CPU?
Geek
4
@Geek accediendo al doble de memoria = el doble de caché desperdiciado (muy aproximadamente).
user253751
49

He utilizado un archivo mapeado en memoria para implementar una función de 'autocompletar' mientras el usuario está escribiendo. Tengo más de 1 millón de números de pieza de productos almacenados en un solo archivo de índice. El archivo tiene información de encabezado típica, pero la mayor parte del archivo es una matriz gigante de registros de tamaño fijo ordenados en el campo clave.

En tiempo de ejecución, el archivo se asigna en memoria, se convierte en una matriz de Cestilo structy hacemos una búsqueda binaria para encontrar números de pieza coincidentes a medida que el usuario escribe. Solo unas pocas páginas de memoria del archivo se leen realmente desde el disco, las páginas que se acceden durante la búsqueda binaria.

  • Simultaneidad: tuve un problema de implementación en el que a veces asignaba la memoria al archivo varias veces en el mismo espacio de proceso. Esto fue un problema, según recuerdo, porque a veces el sistema no podía encontrar un bloque libre lo suficientemente grande de memoria virtual para asignar el archivo. La solución fue mapear el archivo solo una vez y procesar todas las llamadas. En retrospectiva, usar un servicio de Windows completo hubiera sido genial.
  • Acceso aleatorio: la búsqueda binaria es ciertamente acceso aleatorio y ultrarrápida
  • Rendimiento: la búsqueda es extremadamente rápida. A medida que los usuarios escriben, una ventana emergente muestra una lista de números de pieza de productos coincidentes, la lista se reduce a medida que continúan escribiendo. No hay un retraso notable al escribir.
Brian Ensink
fuente
1
¿No sería lenta la búsqueda binaria a medida que se leen las páginas en cada intento? ¿O es el sistema operativo lo suficientemente inteligente como para lidiar con esto de una manera eficiente?
jjxtra
1
Supongo que usar E / S mapeadas en memoria es un desperdicio para la búsqueda binaria, ya que la búsqueda solo accederá a unas pocas claves en ubicaciones de memoria relativamente distantes, pero el sistema operativo se cargará en páginas de 4k para cada solicitud de este tipo. Pero, de nuevo, el archivo con partes no cambia mucho, por lo que la caché ayuda a cubrir esto. Pero estrictamente hablando, creo que la búsqueda / lectura tradicional sería mejor aquí. Finalmente, 1 mil no es mucho en estos días. ¿Por qué no guardarlo todo en la RAM?
el cerdo
5
@the swine y PsychoDad mi respuesta original fue de 2008 y la implementación real de esta función de autocompletar mapeada en memoria fue alrededor de 2004-2005 más o menos. El consumo de 800-1000 MB de memoria física para cargar el archivo completo no fue una buena solución para nuestra base de usuarios. La solución mapeada en memoria fue muy rápida y eficiente. Dio una patada en el culo y lo recuerdo con cariño de mis primeros días de desarrollador junior. :)
Brian Ensink
@BrianEnsink: ok, eso tiene sentido. No esperaba que cada entrada fuera tanto como 1kB. luego, por supuesto, el enfoque paginado se vuelve más eficiente. nice :)
the swine
22

Los archivos asignados en memoria se pueden usar para reemplazar el acceso de lectura / escritura o para admitir el uso compartido simultáneo. Cuando los usa para un mecanismo, obtiene el otro también.

En lugar de buscar, escribir y leer en un archivo, lo asigna a la memoria y simplemente accede a los bits donde espera que estén.

Esto puede ser muy útil y, dependiendo de la interfaz de memoria virtual, puede mejorar el rendimiento. La mejora del rendimiento puede ocurrir porque el sistema operativo ahora puede administrar esta "E / S de archivo" anterior junto con todos sus otros accesos de memoria programáticos, y puede (en teoría) aprovechar los algoritmos de paginación y demás que ya está usando para admitir memoria virtual para el resto de su programa. Sin embargo, depende de la calidad de su sistema de memoria virtual subyacente. Anécdotas He escuchado decir que los sistemas de memoria virtual Solaris y * BSD pueden mostrar mejores mejoras de rendimiento que el sistema VM de Linux, pero no tengo datos empíricos para respaldar esto. YMMV.

La simultaneidad entra en escena cuando se considera la posibilidad de que múltiples procesos utilicen el mismo "archivo" a través de la memoria asignada. En el modelo de lectura / escritura, si dos procesos escribieron en la misma área del archivo, podría estar bastante seguro de que uno de los datos del proceso llegaría al archivo, sobrescribiendo los datos del otro proceso. Obtendría uno u otro, pero no una mezcla extraña. Debo admitir que no estoy seguro de si este es un comportamiento exigido por algún estándar, pero es algo en lo que puede confiar. (¡En realidad es una buena pregunta de seguimiento!)

En el mundo cartografiado, por el contrario, imagine dos procesos que "escriben". Lo hacen haciendo "almacenes de memoria", lo que da como resultado que el O / S pague los datos en el disco, eventualmente. Pero mientras tanto, se puede esperar que ocurran escrituras superpuestas.

He aquí un ejemplo. Digamos que tengo dos procesos que escriben 8 bytes en el desplazamiento 1024. El proceso 1 está escribiendo '11111111' y el proceso 2 está escribiendo '22222222'. Si usan E / S de archivo, entonces puede imaginarse, en el fondo del O / S, hay un búfer lleno de 1 y un búfer lleno de 2, ambos dirigidos al mismo lugar en el disco. Uno de ellos va a llegar primero y el otro un segundo. En este caso, gana el segundo. Sin embargo , si estoy usando el enfoque de archivo mapeado en memoria, el proceso 1 irá a un almacenamiento de memoria de 4 bytes, seguido de otro almacenamiento de memoria de 4 bytes (supongamos que ese no es el tamaño máximo de almacenamiento de memoria). El proceso 2 hará lo mismo. Según cuándo se ejecutan los procesos, puede esperar ver cualquiera de los siguientes:

11111111
22222222
11112222
22221111

La solución a esto es utilizar la exclusión mutua explícita, lo que probablemente sea una buena idea en cualquier caso. De todos modos, confiaba en el SO para hacer "lo correcto" en el caso de E / S de archivo de lectura / escritura.

La primitiva de exclusión mutua de clasificación es el mutex. Para archivos mapeados en memoria, le sugiero que busque un mutex mapeado en memoria, disponible usando (por ejemplo) pthread_mutex_init ().

Edite con un error: cuando está utilizando archivos mapeados, existe la tentación de incrustar punteros a los datos en el archivo, en el propio archivo (piense en la lista vinculada almacenada en el archivo mapeado). No desea hacer eso, ya que el archivo puede estar mapeado en diferentes direcciones absolutas en diferentes momentos o en diferentes procesos. En su lugar, utilice compensaciones dentro del archivo mapeado.

pantano
fuente
1

La concurrencia sería un problema. El acceso aleatorio es más fácil El rendimiento va de bueno a excelente. Facilidad de uso. No tan bueno. Portabilidad - no tan caliente.

Los he usado en un sistema solar hace mucho tiempo, y esos son mis pensamientos.

Paul Nathan
fuente