2010-09-24 8 views
5

Tengo un problema que se describió en varios subprocesos relacionados con la asignación de memoria y un consumo de memoria creciente en Linux.Los archivos asignados a la memoria Linux reservan mucha memoria física

Al abrir un archivo de 1 GB bajo Linux o MacOS X y el mapa en la memoria usando

me.data_begin = mmap(NULL, capacity(me), prot, MAP_SHARED, me.file.handle, 0); 

y secuencialmente leer la memoria asignada, mi programa utiliza cada vez más físico de memoria aunque he usado posix_madvise (incluso llamó varias veces durante el proceso de lectura):

posix_madvise(me.data_begin, capacity(me), MMAP_SEQUENTIAL); 

sin éxito. :-(

Traté:

  • banderas diferentes MMAP_RANDOM, MMAP_DONTNEED, MMAP_NORMAL sin éxito
  • posix_fadvise (me.file.handle, 0, capacidad (yo), POSIX_FADV_DONTNEED) antes y después de llamar a mmap -> sin éxito

Se funciona en Mac OS X !!! cuando combino

posix_madvise(.. MMAP_SEQUENTIAL) 

y

msync(me.data_begin, capacity(me), MS_INVALIDATE). 

La memoria residente está por debajo de 16 M (que se llama periódicamente msync después 16mio etapas).

Pero bajo Linux nada funciona. ¿Alguien tiene una idea o una historia de éxito para mi problema bajo Linux?

Saludos, David

+0

Puede o no ser relevante, pero debería ser útil saber: ¿está utilizando un sistema de 32 bits o de 64 bits? ¿Sabe que no debe mapear un 1GB en un sistema de 32 bits? (incluso si está utilizando un sistema de 64 bits, puede estar preocupado por la portabilidad). – Juliano

+0

Todos los sistemas son de 64 bits (con punteros y desplazamientos de archivos de 64 bits) y pude mapear con éxito archivos de 40 GB. Acabo de reducir el problema a 1 GB por el bien de la reproducibilidad. – Dave

+0

@Sven. Hay casos en que el uso de una asignación de memoria es inevitable, por ejemplo, cuando una llamada a la biblioteca requiere una región de memoria, en lugar de un archivo. Entonces su sugerencia no es útil y no responde la pregunta. En cuanto a la respuesta, aparentemente en MMAP_SEQUENTIAL de Linux está prácticamente * roto *. La parte de lectura anticipada funciona, la parte de recuperación de página no. Y la única manera de sugerirle a Linux que, de hecho, estas páginas son buenos candidatos es desmantelar la región (y mapearla de nuevo). –

Respuesta

8

gestión de memoria Linux es diferente de otros sistemas. El principio clave es que la memoria que no se usa es memoria desperdiciada. En muchos sentidos, Linux intenta maximizar el uso de la memoria, lo que resulta (la mayoría de las veces) en un mejor rendimiento.

No es que "nada funcione" en Linux, pero que su comportamiento es un poco diferente al esperado.

Cuando las páginas de memoria se extraen del archivo mmapped, el sistema operativo tiene que decidir qué páginas de memoria física se liberarán (o intercambiarán) para poder usarlas. Buscará páginas que sean más fáciles de intercambiar (no requiere escritura inmediata en el disco) y es menos probable que se vuelvan a utilizar.

La llamada POSIX madvice() sirve para decirle al sistema cómo utilizará su aplicación las páginas. Pero como su nombre lo indica, es un consejo para que el sistema operativo esté mejor instrumentado al tomar decisiones de búsqueda e intercambio. No es una política ni un orden.

Para demostrar los efectos de madvice() en Linux, modifiqué uno de los ejercicios que doy a mis alumnos. Vea el complete source code here. Mi sistema es de 64 bits y tiene 2 GB de RAM, que ahora está en uso en aproximadamente un 50%. Usando el programa para mapear un archivo de 2 GB, léelo secuencialmente y descartar todo. Informa el uso de RSS cada 200 MB se lee.Los resultados sin madvice ():

<[email protected]> ~% ./madvtest file.dat n 
    0 :  3 MB 
    200 : 202 MB 
    400 : 402 MB 
    600 : 602 MB 
    800 : 802 MB 
    1000 : 1002 MB 
    1200 : 1066 MB 
    1400 : 1068 MB 
    1600 : 1078 MB 
    1800 : 1113 MB 
    2000 : 1113 MB 

Linux mantienen empujando cosas fuera de la memoria hasta alrededor de 1 GB que se leyó. Después de eso, comenzó a presionar el proceso en sí (ya que el otro 50% de la memoria estaba activo por los otros procesos) y se estabilizó hasta el final del archivo.

Ahora, con madvice():

<[email protected]> ~% ./madvtest file.dat y 
    0 :  3 MB 
    200 : 202 MB 
    400 : 402 MB 
    600 : 494 MB 
    800 : 501 MB 
    1000 : 518 MB 
    1200 : 530 MB 
    1400 : 530 MB 
    1600 : 530 MB 
    1800 : 595 MB 
    2000 : 788 MB 

Tenga en cuenta que Linux decidió asignar páginas a que el proceso sólo hasta que alcanzó alrededor de 500 MB, mucho más rápidamente que sin madvice(). Esto se debe a que después de eso, las páginas actualmente en la memoria parecían mucho más valiosas que las páginas marcadas como acceso secuencial por este proceso. Hay un umbral en el VMM que define cuándo comenzar a soltar páginas antiguas del proceso.

Puede preguntar por qué Linux siguió asignando páginas de hasta 500 MB y no se detuvo mucho antes, ya que se marcaron como acceso secuencial. Es que o bien el sistema tenía suficientes páginas de memoria gratuitas de todas formas, o bien las otras páginas para residentes eran demasiado viejas para mantenerse. Entre mantener antiguas páginas en la memoria que ya no parecen ser útiles y traer más páginas para servir a un programa que se ejecuta ahora, Linux elige la segunda opción.

Incluso si se marcaron como acceso secuencial, solo fue un consejo. La aplicación aún puede querer volver a esas páginas y leerlas nuevamente. O otra aplicación en el sistema. La llamada a madvice() dice solo lo que está haciendo la aplicación, Linux toma en consideración la imagen más grande.

+0

Gracias Juliano, ese comportamiento del 50% es interesante. Me pregunto por qué no hay forma de imponer Linux para liberar páginas que nunca vuelva a leer. En su lugar, sacrifica los búferes y las memorias caché del sistema de archivos. En MacOS X el sacrificio de estas posiciones de almacenamiento intermedio del sistema hasta que esté completamente inutilizable. Pero afortunadamente podemos evitar eso a través de * msync (... MS_INVALIDATE) * En Linux, parece ser el comportamiento que observó con madvice que evita que el sistema se estanque. – Dave

+1

@Dave: considere que no tiene sentido liberar prematuramente esas páginas. Linux no está sacrificando cachés y búferes, sino que está haciendo exactamente eso. A medida que lea más datos del disco, Linux tiene que traerlos a la memoria de todos modos. En cierto modo almacena en caché lo que se leyó en el disco, pero en lugar de contabilizarlo como "caché", lo cuenta como parte de la RSS del proceso que mapeó ese archivo. Cuando Linux necesita caché nuevamente, liberará las páginas mapeadas a esa aplicación. ¡No necesita preocuparse por eso! – Juliano

+0

@Juliano: considere que MADV_SEQUENTIAL le dice específicamente al sistema que se va a acceder a las páginas mediante lectura secuencial solo una vez. Estas páginas son candidatos perfectos para reclamar.En cambio, veo que en mi caja, hasta que se alcanza el 50% de la memoria (32 GB en ese caso), se está reclamando la memoria caché de archivos. Y veo que el rendimiento de otros procesos es degradante, Ahora he encontrado una manera ridícula de forzar a Linux a no hacer eso. Al desempacar y mapear el archivo nuevamente, cada 1Gb más o menos. Eso * SÍ * resuelve el problema y después de eso no veo la degradación del rendimiento para otros procesos. –

Cuestiones relacionadas