1. Qué es un fallo de página
Un fallo de página (page fault) ocurre cuando un proceso accede a una página cuya entrada en la tabla de páginas tiene el bit presente a 0. La MMU no puede traducir la dirección y lanza una excepción al procesador, que transfiere el control al sistema operativo.
El fallo de página es el mecanismo que hace posible la memoria virtual: permite que las páginas se carguen solo cuando se necesitan.
Fallo de página es la excepción que lanza la MMU cuando un acceso a memoria se refiere a una página no presente en la RAM, transfiriendo el control al sistema operativo para que la cargue.
2. Los pasos del fallo de página
El proceso completo tiene estos pasos:
- El programa accede a una dirección virtual cuya página no está presente.
- La MMU detecta P=0 y lanza una excepción de fallo de página (trap).
- El procesador guarda el estado (registros, PC) y transfiere el control al manejador de fallos del SO.
- El SO identifica la página que falta (usando la dirección virtual que causó el fallo).
- El SO busca un marco libre (o reemplaza uno si no hay).
- El SO carga la página desde el disco (swap o archivo) al marco.
- El SO actualiza la tabla de páginas: P=1, marco=f, y actualiza los bits.
- El SO reanuda la instrucción que causó el fallo.
3. Lo que hace el hardware
El hardware (MMU + procesador) es responsable de:
- Detectar P=0: en cada acceso, la MMU comprueba el bit presente de la PTE.
- Lanzar la excepción: si P=0, la MMU lanza un trap (fallo de página) y guarda la dirección virtual que causó el fallo en un registro (CR2 en x86).
- Guardar el estado: el procesador guarda los registros y el PC, y transfiere el control al manejador del SO.
Todo esto ocurre en hardware, en unos pocos ciclos. El SO no interviene hasta que la excepción se lanza.
4. Lo que hace el sistema operativo
El manejador de fallos de página del SO realiza:
- Identificar la página: lee el registro que contiene la dirección virtual que causó el fallo (CR2 en x86).
- Verificar que el acceso sea válido: comprueba que la dirección esté dentro del espacio del proceso y que los permisos sean correctos. Si no, envía SIGSEGV.
- Buscar un marco libre: si hay marcos libres, se usa uno. Si no, se elige una víctima (reemplazo, tema 34).
- Cargar la página: si la página está en el swap, se lee del disco. Si es la primera vez, se inicializa a cero (páginas anónimas) o se lee del archivo (páginas de archivo).
- Actualizar la tabla: se establece P=1, se pone el marco, y se actualizan los bits (accessed, dirty, etc.).
- Reanudar: se devuelve el control al proceso.
El SO también puede prefetchear páginas adyacentes (leer varias a la vez) para mejorar el rendimiento.
5. Reanudar la instrucción
Tras cargar la página, el SO reanuda la instrucción que causó el fallo. Esto es posible porque:
- El procesador guardó el PC (program counter) al entrar al manejador.
- La instrucción que causó el fallo no se completó (no se escribió el resultado).
- Al reanudar, la instrucción se re-ejecuta, pero ahora la página está presente, por lo que tiene éxito.
Esto es transparente para el programa: no se entera de que hubo un fallo de página.
6. Tipos de fallo de página
| Tipo | Causa | Acción del SO |
|---|---|---|
| Menor (minor) | La página está en la RAM pero no mapeada (ej. página ya cargada por otro proceso, o página COW). | Mapear la página sin leer del disco. Rápido. |
| Mayor (major) | La página no está en la RAM; hay que leerla del disco. | Leer del disco y cargar en la RAM. Lento. |
| Inválido | La dirección no es válida (fuera del espacio del proceso). | Enviar SIGSEGV al proceso. |
Los fallos menores son rápidos (microsegundos); los mayores son lentos (milisegundos). La distinción es importante para el rendimiento.
7. Ejemplo numérico
Un programa accede a una dirección virtual 0x1234 cuya página (p=2) no está presente. La tabla de páginas tiene:
| Página | Marco | Presente |
|---|---|---|
| 0 | 5 | Sí |
| 1 | 2 | Sí |
| 2 | — | No |
| 3 | 8 | Sí |
El acceso a 0x1234 (p=2) genera un fallo de página. El SO carga la página 2 en un marco libre (ej. marco 3), actualiza la tabla (página 2 → marco 3, P=1) y reanuda la instrucción. El acceso se repite y ahora tiene éxito.
8. Experimento en C
El programa siguiente provoca un fallo de página manejable usando mmap con PROT_NONE y luego cambiando los permisos:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
int main(void)
{
size_t tam = 4096;
char *p = mmap(NULL, tam, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED) { perror("mmap"); return 1; }
printf("Región mapeada en %p (sin permisos)\\n", (void *)p);
printf("Voy a cambiar permisos a PROT_READ|PROT_WRITE...\\n");
if (mprotect(p, tam, PROT_READ | PROT_WRITE) == -1) { perror("mprotect"); return 1; }
printf("Ahora escribo en la página...\\n");
p[0] = 42; /* esto puede provocar un fallo de página menor */
printf("Leí: %d\\n", p[0]);
munmap(p, tam);
return 0;
}
$ gcc -std=c17 -Wall -Wextra -o pagefault pagefault.c
$ ./pagefault
Región mapeada en 0x7f8b4c000000 (sin permisos)
Voy a cambiar permisos a PROT_READ|PROT_WRITE...
Ahora escribo en la página...
Leí: 42Leí: 42
El programa mapea una región sin permisos, cambia los permisos con mprotect y escribe. El sistema puede generar un fallo de página menor al cargar la página en la RAM.
9. Probar con un simulador
Este simulador muestra los pasos de un fallo de página para una dirección virtual cuya página no está presente.
Simulador · fallo de página
| Paso | Descripción |
|---|---|
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 |
10. En Linux
Linux maneja los fallos de página en el manejador do_page_fault. Las herramientas para observarlos:
$ grep pgfault /proc/vmstat
pgfault 1234567
pgmajfault 890
$ perf stat -e page-faults,major-faults ./pagefault
pgfault: número total de fallos de página (menores + mayores).pgmajfault: número de fallos mayores (lectura del disco).perf stat -e page-faults,major-faults: cuenta los fallos por programa.
11. Resumen
- Un fallo de página ocurre cuando se accede a una página no presente (P=0).
- El hardware detecta el fallo y transfiere el control al SO.
- El SO identifica la página, busca un marco, carga la página y actualiza la tabla.
- La instrucción se reanuda y tiene éxito.
- Hay fallos menores (rápidos) y mayores (lentos, requieren disco).
- Los fallos inválidos provocan SIGSEGV.
12. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta.
1. ¿Qué es un fallo de página?
La excepción que lanza la MMU cuando se accede a una página no presente en la RAM.
2. ¿Qué hace el hardware en un fallo de página?
Detecta P=0, lanza un trap y guarda la dirección virtual que causó el fallo.
3. ¿Qué hace el SO en un fallo de página?
Identifica la página, busca un marco, carga la página, actualiza la tabla y reanuda la instrucción.
4. ¿Cómo se reanuda la instrucción?
El procesador restaura el PC guardado y re-ejecuta la instrucción (ahora la página está presente).
5. ¿Qué es un fallo menor (minor)?
Un fallo en el que la página está en la RAM pero no mapeada (no requiere leer del disco).
6. ¿Qué es un fallo mayor (major)?
Un fallo que requiere leer la página desde el disco (swap o archivo).
7. ¿Qué ocurre si el acceso es inválido?
El SO envía SIGSEGV al proceso.
8. ¿Qué registro guarda la dirección que causó el fallo en x86?
CR2.
Para practicar
- Modifica el simulador para que una página esté presente desde el principio (sin fallo).
- Explica por qué la instrucción se re-ejecuta y no se "salta".
- Investiga cómo Linux distingue entre un fallo menor y uno mayor.
- Usa
perf statpara contar los fallos de página de un programa que toca 1 MiB. - Explica qué ocurre si el SO no puede encontrar un marco libre.
- Dibuja el flujo completo de un fallo de página, desde el hardware hasta la reanudación.
- Compara el tiempo de un fallo menor y uno mayor.