2011-08-12 15 views
10

Tengo un pequeño programa de ejemplo que simplemente fopen es un archivo y usa fgets para leerlo. Usando strace, noté que la primera llamada al fgets ejecuta una llamada al sistema mmap, y luego las llamadas al sistema de lectura se utilizan para leer el contenido del archivo. en fclose, el archivo es munmap ed. Si en cambio abro el archivo con abrir/leer directamente, obviamente esto no ocurre. Tengo curiosidad sobre cuál es el propósito de este mmap y qué está logrando.¿Por qué fopen/fgets utiliza tanto mmap como las llamadas al sistema de lectura para acceder a los datos?

En mi sistema basado en Linux 2.6.31, cuando bajo mucha demanda de memoria virtual estos mmap s a veces se cuelgan durante varios segundos, y me parece que no es necesario.

El código de ejemplo:

#include <stdlib.h> 
#include <stdio.h> 
int main() 
{ 
    FILE *f; 
    if (NULL == (f=fopen("foo.txt","r"))) 
    { 
    printf ("Fail to open\n"); 
    } 
    char buf[256]; 
    fgets(buf,256,f); 
    fclose(f); 
} 

Y aquí está la salida relevante strace cuando se ejecuta el código anterior:

open("foo.txt", O_RDONLY)    = 3 
fstat64(3, {st_mode=S_IFREG|0644, st_size=9, ...}) = 0 
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb8039000 
read(3, "foo\nbar\n\n"..., 4096)  = 9 
close(3)        = 0 
munmap(0xb8039000, 4096)    = 0 

Respuesta

15

No es el archivo que es mmap 'ed - en este caso mmap se usa de forma anónima (no en un archivo), probablemente para asignar memoria al búfer que usarán las lecturas consecuentes.

malloc de hecho da como resultado una llamada a mmap. Del mismo modo, el munmap corresponde a una llamada al free.

+1

Interesante. Por lo tanto, de esto se deduce que todas las operaciones de lectura en FILE * realmente no se leen en el búfer proporcionado, sino en un búfer adicional asignado en el montón y luego se copian en mi búfer. Además, ¿malloc siempre da como resultado una llamada a mmap? Siempre pensé que Heap se administraba localmente en el espacio de usuario y las llamadas al sistema solo se realizaban si se necesitaba agregar más memoria al espacio de direcciones del proceso. También siempre pensé que sbrk/brk se usaba para esto, no para mmap. – bdk

+5

@bdk: Sí, las funciones de archivo de la biblioteca estándar (no las llamadas al sistema) mantienen su propio búfer de forma que cuando se invoca 'fgets (buf, 1, f)' continuamente en un bucle, no da como resultado cientos de llamadas al sistema 'leer'. 'malloc' da como resultado un' mmap' cuando no tiene más espacio disponible en el espacio de usuario; por ejemplo, el primer 'malloc (8)' puede dar como resultado 'mmap (4096)', y consecuente 'malloc (8) '' devolverá punteros al área ya asignada hasta que se agote. –

+0

Gracias! Eso lo explica. Cada vez que uso strace para intentar rastrear algo, termino aprendiendo algo nuevo. – bdk

1

desde lo que he leído funciones de asignación de memoria son útiles al manejar archivos de gran tamaño. ahora la definición de grande es algo de lo que no tengo idea. pero sí para los archivos de gran tamaño, son significativamente más rápidos en comparación con las llamadas de E/S "en búfer".

en el ejemplo que ha publicado creo que el archivo se abre con la función open() y mmap se usa para asignar memoria u otra cosa.

de la sintaxis de la función mmap esto se puede ver con claridad:

void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);

el segundo parámetro última toma el descriptor de archivo que debería ser no negativo. mientras está en el seguimiento de la pila es -1

+0

Esto está mal. En POSIX stdio no se puede implementar con 'mmap' debido a una semántica incorrecta cuando el archivo se trunca (se bloqueará con' SIGBUS' en lugar de dar un error). El 'mmap' OP pregunta sobre no es un mapa del archivo; es simplemente una asignación de memoria anónima. –

+0

eso es lo que he dicho "mmap se usa para asignar memoria o algo más" ... No dije que mmap se usa para mmapping 'the' file. –

+0

Oh, interpreté mal "útil" como "usado". ¡Lo siento! –

5

El mmap no está mapeando el archivo; en su lugar, está asignando memoria para el almacenamiento intermedio de stdio FILE. Normalmente malloc no usaría mmap para dar servicio a una asignación tan pequeña, pero parece que la implementación stdio de glibc está usando mmap directamente para obtener el búfer. Esto es probablemente para asegurarse de que está alineado con la página (aunque posix_memalign podría lograr lo mismo) y/o para asegurarse de que al cerrar el archivo se devuelve la memoria del búfer al kernel. Cuestiono la utilidad de la alineación de páginas del búfer. Presumiblemente es para el rendimiento, pero no veo ninguna manera de que sea útil a menos que el desplazamiento del archivo del que está leyendo también esté alineado con la página, e incluso entonces parece una micro-optimización dudosa.

Cuestiones relacionadas