1 of 15

Archivos mapeados en memoria

Notas sobre mmap(), munmap() y otras llamadas al sistema relacionadas

2 of 15

Reserva de memoria en C++

  • En un programa hay varias formas de reservar memoria en tiempo de ejecución:
    1. Mediante variables automáticas:�char username[5120];�
    2. Mediante reserva dinámica de memoria:�char* username = new char[5120];�
    3. Mediante mmap():�char* username = mmap(nullptr, 5120,� PROT_READ | PROT_WRITE,� MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

3 of 15

Variables automáticas

  • La memoria se reserva y se libera automáticamente:
    • Al entrar y salir de los distintos alcances (scopes) del código.
    • Siempre se reservan en la pila del hilo.
  • Se usa con las variables locales.

4 of 15

Reserva dinámica

  • La memoria se reserva manualmente:
    • Se reserva con el operador new y se libera con el operador delete, implementados en la librería estándar de C++
    • Están optimizados para reservas de pequeño tamaño.
    • Se reserva del montón (heap) del proceso cuando la región a reservar es pequeña (<128KB).
  • Todos los hilos tienen acceso pues comparten el montón.
  • Con reservas grandes el operador new invoca a mmap() directamente.

5 of 15

mmap()

  • La memoria se reserva manualmente:
    • Se reserva con la llamada al sistema mmap() y se libera con munmap().
    • La memoria se pide directamente al sistema operativo, sin que la librería estándar de C++ sepa nada.
    • Se reserva de la región entre el montón y la pila.
  • Todos los hilos tienen acceso pues también comparten esta región.
  • Se reserva en múltiplos del tamaño de página (generalmente 4KB).

6 of 15

Reserva de memoria en C++

Proceso

Código (.text)

BSS

Montón

Pila

Variables automáticas

char user[5120];

Reserva dinámica de memoria

char* user = new char[5120];

Variables globales y estáticas no inicializadas o inicializadas 0

Con mmap()

char* user = mmap(nullptr, 5120,� PROT_READ | PROT_WRITE,� MAP_PRIVATE | MAP_ANONYMOUS,� -1, 0);

7 of 15

Memoria anónima

  • La memoria reservada con mmap() es privada al proceso y anónima.�mmap(nullptr, 5120, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  • Si falta RAM, se respalda sobre el archivo / partición de intercambio (swap) del sistema.

¿Y si le pudiéramos pedir que se respalde sobre un archivo cualquiera?

8 of 15

Archivos mapeados en memoria

Proceso

Código (.text)

BSS

Montón

Pila

Archivo mapeado

Región mapeada del archivo

Archivo mapeado

length

offset

mmap(nullptr, length,� PROT_READ | PROT_WRITE, MAP_SHARED,� fd, offset);

9 of 15

Archivos mapeados en memoria

  • Permiten acceder a un archivo directamente como parte del espacio de direcciones virtual del proceso.
  • En el primer acceso a una página mapeada se produce un fallo de página que es resuelto por el sistema operativo leyendo la porción del archivo correspondiente a la página.
  • El sistema operativo escribe periódicamente las páginas modificadas.

10 of 15

Archivos mapeados en memoria

  • Otros parámetros de mmap():
    • fd, descriptor del archivo a mapear�int fd = open("nombre", O_RDWR | … );�char *user = mmap(nullptr, length,� PROT_READ | PROT_WRITE, MAP_SHARED,� fd, offset);
    • prot, permisos de acceso a la memoria mapeada.
      • Deben ser coherentes con el modo de acceso al archivo.
      • Por ejemplo PROT_READ | PROT_WRITE con O_RDWR en open(), para lectura y escritura.

11 of 15

new de emplazamiento

  • ¿Cómo construir un objeto de C++ en una región de memoria previamente reservada con mmap()?
    1. Suponiendo que addr es un puntero dentro de la región mapeada / reservada…
    2. … y que queremos crear un objeto de la clase Message:

Message* message = new(addr) Message;

12 of 15

Desmapear un región

  • Al terminar se puede desmaperar un región que empieza en addr y de tamaño length con mumap():�mummap(addr, length);

13 of 15

Mmap en Windows

  • En Windows se usa VirtualAlloc() y VirtualFree().
  • VirtualAlloc(), reserva memoria en el espacio de direcciones del proceso actual. Como mmap().
  • VirtualAllocEx(), igual que VirtualAlloc() pero puede hacerlo en el espacio de direcciones de un proceso diferente.
  • VirtualFree(), libera regiones reservadas con VirtualAlloc(). Como munmap().
  • VirtualFreeEx(), libera regiones reservadas con VirtualAllocEx().

14 of 15

Acceso concurrente

  • Es necesario tomar medidas si el acceso concurrente puede causar problemas.
  • Entre hilos de un mismo proceso, se pueden usar mutex, semáforos, etc.
  • Entre distintos procesos, se puede usar la llamada al sistema flock()
    • Bloquea de forma “sugerida” el acceso al archivo.
    • El bloqueo sólo funciona entre procesos distintos, no entre hilos de un mismo proceso.
    • Multiple threads able to get flock at the same time.

15 of 15

Memoria compartida

  • Hay otros recursos que el sistema ofrece como un descriptor de archivos y se pueden mapear.
    • Dispositivos. Por ejemplo el framebuffer (/dev/fb), que representa la memoria de vídeo. Esto permite acceder a la memoria de vídeo desde la memoria del del proceso.
    • Memoria compartida. Con la llamada shm_open() se puede crear un objeto de memoria compartida, que después se mapea en cada proceso mediante mmap().
    • También se puede compartir memoria con procesos hijos si se reserva como anónima y MAP_SHARED antes de hacer el fork():�mmap(..., PROT_READ | PROT_WRITE,� MAP_SHARED | MAP_ANONYMOUS, -1, 0);