1. El problema: elegir el tamaño
El tamaño de página es una decisión de diseño de la arquitectura. No se puede cambiar fácilmente: afecta a la MMU, a la tabla de páginas, a la TLB y a todo el sistema operativo. Una vez elegido, todos los procesos usan ese tamaño.
La pregunta es: ¿qué tamaño minimiza el costo total? La respuesta depende del tipo de carga de trabajo y del hardware.
2. Tamaños típicos
| Tamaño | Uso típico | Arquitectura |
|---|---|---|
| 4 KiB (212) | Estándar en x86, ARM, RISC-V | Casi todas |
| 16 KiB | Algunos sistemas ARM (Apple Silicon) | ARM64 |
| 64 KiB | Algunos sistemas PowerPC, ARM | PowerPC, ARM |
| 2 MiB (221) | Páginas grandes (huge pages) | x86-64 |
| 1 GiB (230) | Páginas gigantes (gigantic pages) | x86-64 |
El tamaño más común es 4 KiB. Las páginas grandes se usan de forma opt-in para aplicaciones específicas (bases de datos, máquinas virtuales).
3. Fragmentación interna
La paginación elimina la fragmentación externa, pero introduce fragmentación interna: el último bloque de cada proceso (su última página) puede no estar completo. Si un proceso usa 10000 bytes con páginas de 4096, necesita 3 páginas (12288 bytes), desperdiciando 2288 bytes en la última.
Fragmentación interna = (número de páginas × tamaño de página) − tamaño del proceso. En promedio, es la mitad de una página por proceso.
Con páginas más grandes, la fragmentación interna es mayor. Con 100 procesos y páginas de 4 KiB, se desperdician ~200 KiB en promedio. Con páginas de 2 MiB, se desperdician ~100 MiB.
4. Costos de cada opción
| Factor | Página pequeña (4 KiB) | Página grande (2 MiB) |
|---|---|---|
| Fragmentación interna | Baja (~2 KiB/proceso) | Alta (~1 MiB/proceso) |
| Tamaño de la tabla de páginas | Grande (muchas entradas) | Pequeño (pocas entradas) |
| Fallos de TLB | Muchos (más páginas) | Pocos (menos páginas) |
| Transferencias de disco | Pequeñas (4 KiB) | Grandes (2 MiB) |
| Flexibilidad | Alta (granular) | Baja (gruesa) |
La tabla de páginas para un proceso de 1 GiB con páginas de 4 KiB tiene 262144 entradas (2 MiB de tabla). Con páginas de 2 MiB, solo 512 entradas (4 KiB de tabla). Las páginas grandes reducen drásticamente el overhead de la tabla y de la TLB.
5. El compromiso
No hay un tamaño óptimo universal. La elección depende de:
- Tamaño de la memoria física: con más RAM, las tablas son más grandes y las páginas grandes ayudan.
- Tipo de carga de trabajo: aplicaciones con grandes arrays contiguos (bases de datos, simulaciones) se benefician de páginas grandes.
- Número de procesos: con muchos procesos pequeños, páginas pequeñas reducen la fragmentación interna.
- TLB: con una TLB pequeña, páginas grandes reducen los fallos.
Por eso la tendencia es usar 4 KiB por defecto y permitir páginas grandes de forma opt-in.
6. Páginas grandes (huge pages)
Las huge pages son páginas de 2 MiB (o 1 GiB) que se usan para regiones de memoria grandes y contiguas. El SO las gestiona por separado: se reservan al arrancar o se asignan dinámicamente.
- Ventaja: menos entradas en la tabla, menos fallos de TLB, transferencias más eficientes.
- Inconveniente: fragmentación interna mayor, requieren memoria contigua libre, gestión más compleja.
- Uso típico: bases de datos (Oracle, PostgreSQL), máquinas virtuales (KVM), aplicaciones científicas.
En Linux, las huge pages se configuran con hugetlbfs o con mmap con MAP_HUGETLB.
7. Ejemplo numérico
Proceso de 1 MiB (1048576 bytes). Comparación con distintos tamaños de página:
| Tamaño de página | Páginas necesarias | Memoria asignada | Fragmentación interna | Entradas en tabla |
|---|---|---|---|---|
| 4 KiB | 256 | 1048576 B | 0 B | 256 |
| 2 MiB | 1 | 2097152 B | 1048576 B | 1 |
Con 4 KiB no hay fragmentación (1 MiB es múltiplo de 4 KiB), pero se necesitan 256 entradas en la tabla. Con 2 MiB solo 1 entrada, pero se desperdicia 1 MiB.
8. Experimento en C
El programa siguiente consulta el tamaño de página y calcula la fragmentación para distintos tamaños:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
long ps = sysconf(_SC_PAGESIZE);
printf("Tamaño de página: %ld bytes (%ld KiB)\\n", ps, ps / 1024);
size_t tamanios[] = {1000, 4096, 10000, 1048576};
long paginas[] = {256, 1024, 4096, 2097152}; /* tamaños de página a probar */
for (int j = 0; j < 4; j++) {
printf("\\nCon página de %ld bytes:\\n", paginas[j]);
for (int i = 0; i < 4; i++) {
size_t proc = tamanios[i];
size_t npag = (proc + paginas[j] - 1) / paginas[j];
size_t asignado = npag * paginas[j];
size_t frag = asignado - proc;
printf(" proceso %6zu B -> %3zu páginas, %6zu B asignados, frag %5zu B\\n",
proc, npag, asignado, frag);
}
}
return 0;
}
$ gcc -std=c17 -Wall -Wextra -o tamanio tamanio.c
$ ./tamanio
Tamaño de página: 4096 bytes (4 KiB)
Con página de 256 bytes:
proceso 1000 B -> 4 páginas, 1024 B asignados, frag 24 B
proceso 4096 B -> 16 páginas, 4096 B asignados, frag 0 B
proceso 10000 B -> 40 páginas, 10240 B asignados, frag 240 B
proceso 1048576 B -> 4096 páginas, 1048576 B asignados, frag 0 B
Con página de 4096 bytes:
proceso 1000 B -> 1 páginas, 4096 B asignados, frag 3096 B
proceso 4096 B -> 1 páginas, 4096 B asignados, frag 0 B
proceso 10000 B -> 3 páginas, 12288 B asignados, frag 2288 B
proceso 1048576 B -> 256 páginas, 1048576 B asignados, frag 0 B
Con página de 2097152 bytes:
proceso 1000 B -> 1 páginas, 2097152 B asignados, frag 2096152 B
proceso 4096 B -> 1 páginas, 2097152 B asignados, frag 2093056 B
proceso 10000 B -> 1 páginas, 2097152 B asignados, frag 2087152 B
proceso 1048576 B -> 1 páginas, 2097152 B asignados, frag 1048576 B proceso 1048576 B -> 1 páginas, 2097152 B asignados, frag 1048576 B
9. Probar con un simulador
Este simulador calcula la fragmentación interna para un proceso de tamaño dado y distintos tamaños de página.
Simulador · tamaño de página y fragmentación
| Medida | Valor |
|---|---|
| Páginas necesarias | |
| Memoria asignada (bytes) | |
| Fragmentación interna (bytes) | |
| Fragmentación interna (%) | |
| Entradas en tabla de páginas |
10. En Linux
Linux usa 4 KiB por defecto, pero soporta páginas grandes (huge pages) de 2 MiB y 1 GiB. La configuración:
$ getconf PAGESIZE
4096
$ cat /proc/meminfo | grep -i huge
HugePages_Total: 0
HugePages_Free: 0
Hugepagesize: 2048 kB
getconf PAGESIZE: tamaño de página estándar (4 KiB)./proc/meminfo: muestra información sobre huge pages.Hugepagesize: tamaño de las huge pages (2048 KiB = 2 MiB).- Para usar huge pages:
mmapconMAP_HUGETLBo montarhugetlbfs.
11. Resumen
- El tamaño de página es un compromiso entre fragmentación interna y overhead de la tabla/TLB.
- Páginas pequeñas (4 KiB): baja fragmentación, tablas grandes, más fallos de TLB.
- Páginas grandes (2 MiB): alta fragmentación, tablas pequeñas, pocos fallos de TLB.
- Las huge pages se usan para regiones grandes y contiguas (bases de datos, VMs).
- En Linux, el tamaño estándar es 4 KiB, consultable con getconf PAGESIZE.
12. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta.
1. ¿Qué es la fragmentación interna en paginación?
El espacio desperdiciado en la última página de un proceso, que no está completamente usada.
2. ¿Cuál es la fragmentación interna promedio?
Aproximadamente la mitad de una página por proceso.
3. ¿Por qué páginas más grandes reducen el overhead de la tabla?
Porque se necesitan menos entradas para cubrir el mismo espacio virtual.
4. ¿Por qué páginas más grandes aumentan la fragmentación interna?
Porque la última página desperdicia más espacio en promedio.
5. ¿Qué son las huge pages?
Páginas de 2 MiB (o 1 GiB) que se usan para regiones grandes y contiguas.
6. ¿Qué ventaja tienen las huge pages para la TLB?
Reducen el número de entradas necesarias, disminuyendo los fallos de TLB.
7. ¿Cómo se consulta el tamaño de página en Linux?
Con getconf PAGESIZE (4096 por defecto).
8. ¿En qué casos se usan huge pages?
Bases de datos, máquinas virtuales y aplicaciones científicas con grandes arrays contiguos.
Para practicar
- Calcula la fragmentación interna para un proceso de 1000 bytes con páginas de 256, 1024 y 4096 bytes.
- Modifica
tamanio.cpara calcular la fragmentación total para 100 procesos de tamaño aleatorio. - Explica por qué las huge pages no son el tamaño por defecto.
- Investiga cómo se configuran las huge pages en Linux (sysctl vm.nr_hugepages).
- Compara el número de entradas en la tabla de páginas para 1 GiB con páginas de 4 KiB vs 2 MiB.
- Usa
mmapconMAP_HUGETLBpara reservar memoria con huge pages. - Dibuja la fragmentación interna para 3 procesos con páginas de 4 KiB.