3 puntos por GN⁺ 2025-11-05 | Aún no hay comentarios. | Compartir por WhatsApp
  • Explica la estructura de memoria de los procesos en Linux al nivel de funcionamiento real, detallando paso a paso la relación entre el espacio de direcciones virtuales y la memoria física
  • Describe de forma concreta cómo un proceso posee y accede a la memoria, centrándose en mecanismos clave como page tables, VMA, mmap, page fault y CoW
  • Presenta cómo observar el estado de memoria por proceso mediante el sistema de archivos /proc, así como el papel de herramientas avanzadas de diagnóstico como pagemap y kpageflags
  • Aborda la optimización de rendimiento y las técnicas de dirty tracking en espacio de usuario mediante funciones recientes del kernel como Transparent Huge Pages (THP), userfaultfd y PAGEMAP_SCAN
  • También explica principios de diseño del kernel relacionados con seguridad y rendimiento, como PTI para mitigar Meltdown, flush de TLB y la política W^X, ofreciendo una comprensión integral de la gestión de memoria en Linux

Estructura básica de la memoria de procesos

  • Cuando un programa se ejecuta, parece que dispone de una enorme memoria continua, pero en realidad el kernel de Linux la organiza dinámicamente en unidades de páginas
    • La CPU consulta las page tables para traducir direcciones virtuales a frames físicos
    • Si no existe un mapeo, ocurre un page fault, y el kernel asigna una nueva página o devuelve un error
  • Si falta RAM física, el kernel mueve páginas sin uso al disco o elimina páginas de archivo para liberar espacio
  • /proc es un sistema de archivos virtual construido por el kernel en memoria, que expone el estado de los procesos y del kernel en forma de archivos

Espacio de direcciones y VMA

  • Cada proceso tiene un objeto de espacio de direcciones, compuesto internamente por varias VMA (Virtual Memory Area)
    • Una VMA es un rango contiguo de direcciones con los mismos permisos (R/W/X) y el mismo backend (memoria anónima o archivo)
  • Las page tables son estructuras consultadas por el hardware y almacenan la información de mapeo (PTE) entre páginas virtuales y físicas
  • Los cambios en el espacio de direcciones se realizan con tres llamadas al sistema
    • mmap: crea una nueva región
    • mprotect: cambia permisos
    • munmap: elimina un mapeo
  • La página es la unidad base de 4 KiB, y algunos sistemas también admiten páginas grandes de 2 MiB y 1 GiB

Ver la composición de memoria con /proc/self/maps

  • Con el comando cat /proc/self/maps se puede revisar el mapa de memoria del proceso
    • Aparecen el código, datos y bss del ejecutable, el heap, mapeos anónimos, bibliotecas compartidas, la pila, etc.
  • Las regiones [vdso] y [vvar] son código y datos para llamadas al sistema rápidas mapeados por el kernel

Cómo funciona mmap

  • mmap no asigna memoria real de inmediato, sino que registra una promesa sobre el espacio de direcciones
    • Las páginas se asignan en el momento del primer acceso
  • Al mapear archivos, offset debe estar alineado a página, y acceder más allá del final del archivo provoca SIGBUS
  • MAP_SHARED se refleja directamente en el archivo, mientras que MAP_PRIVATE crea páginas independientes mediante Copy-on-Write (CoW) al escribir
  • MAP_FIXED_NOREPLACE mejora la seguridad al fallar si ya existe un mapeo en la dirección indicada

Primer acceso y page fault

  • En el primer acceso a un mapeo nuevo, si la CPU no encuentra la entrada en la page table, ocurre un page fault
    • El kernel verifica la validez de la dirección, los permisos de acceso y la existencia del recurso
    • Si es un mapeo anónimo, asigna una nueva página rellenada con ceros; si es un mapeo de archivo, la lee desde la page cache
  • Un minor fault ocurre cuando los datos ya están en RAM; un major fault, cuando hace falta I/O de disco
  • La pila está protegida con una guard page, por lo que un acceso demasiado hacia abajo provoca SIGSEGV

Copy-on-Write de fork() y MAP_PRIVATE

  • Al hacer fork, padre e hijo comparten las mismas páginas físicas, marcadas como solo lectura
    • Solo en el momento de escritura se copia una nueva página para mantener la independencia
  • Los mapeos de archivo con MAP_PRIVATE funcionan con el mismo principio
  • Opciones relacionadas
    • vfork: comparte el espacio de direcciones del padre
    • clone(CLONE_VM): crea un hilo
    • MADV_DONTFORK, MADV_WIPEONFORK: excluyen el mapeo del proceso hijo o lo inicializan en cero

Cambio de permisos e invalidación del TLB

  • Cuando mprotect cambia los permisos de una página, el kernel divide la VMA y modifica las page tables, y luego realiza la invalidación del TLB
  • Según la política W^X, una página no puede ser escribible y ejecutable al mismo tiempo
  • El TLB (Translation Lookaside Buffer) es una caché de traducciones recientes de direcciones, y su invalidación provoca una pequeña pausa

Observación detallada mediante /proc

  • Con /proc/<pid>/maps, smaps y smaps_rollup se pueden revisar permisos por región, RSS y uso de HugePage
  • /proc/<pid>/pagemap ofrece estado por página (presencia, swap, PFN, etc.), aunque el PFN no está disponible para usuarios normales
  • /proc/kpagecount y /proc/kpageflags muestran el número de mapeos por PFN y propiedades de la página (anónima, de archivo, dirty, etc.)
  • Con mincore y SEEK_DATA/SEEK_HOLE se pueden identificar regiones de datos y huecos en archivos dispersos
  • Al combinar PAGEMAP_SCAN y userfaultfd, es posible implementar dirty tracking en espacio de usuario

Transparent Huge Pages (THP) y mTHP

  • THP agrupa automáticamente la memoria de acceso frecuente en páginas grandes (como 2 MiB) para mejorar la eficiencia del TLB
    • El hilo khugepaged fusiona páginas adyacentes
  • mTHP admite páginas grandes variables (folio) de distintos tamaños, como 16 KiB y 64 KiB
  • En /proc/self/smaps, AnonHugePages y FilePmdMapped permiten verificar su uso
  • La configuración global del sistema se administra en /sys/kernel/mm/transparent_hugepage/
  • Se puede controlar por región con MADV_HUGEPAGE y MADV_NOHUGEPAGE

Dirty tracking en espacio de usuario

  • Con userfaultfd y PAGEMAP_SCAN se pueden copiar solo las páginas modificadas
    • El kernel realiza el escaneo y la protección contra escritura en una sola operación atómica
    • Es eficiente para snapshots, live migration y casos similares

Mecanismo de flush del TLB

  • En x86, la invalidación del TLB se hace de dos maneras
    • INVLPG: invalida una sola página
    • Recargar la raíz de las page tables para hacer un flush completo
  • PCID e INVPCID permiten la gestión de etiquetas de TLB por proceso, reduciendo flushes innecesarios
  • tlb_single_page_flush_ceiling es el umbral con el que el kernel decide entre flush por página o flush completo

Mitigación de Meltdown: Page Table Isolation (PTI)

  • Meltdown es una vulnerabilidad en la que datos del kernel pueden quedar expuestos a través de la caché durante la ejecución especulativa
  • Linux usa PTI (Page Table Isolation) para separar los espacios de direcciones de usuario y kernel
    • Al entrar, cambia CR3 para usar page tables exclusivas del kernel
    • Aprovecha PCID para minimizar el flush del TLB
  • Está activado por defecto y puede deshabilitarse con nopti

Procedimiento seguro del kernel para cambiar mapeos

  • Al modificar un mapeo, el orden es
    1. Procesar las reglas de caché
    2. Modificar las page tables
    3. Invalidar el TLB
  • Los mapeos internos del kernel (vmap, vmalloc) también sincronizan caché y TLB antes y después de I/O
  • Algunas arquitecturas requieren flush de la instruction cache después de copiar código

Estructura de pila y llamadas en x86

  • En modo de 64 bits se usan los registros RIP, RSP y RBP, y la pila crece hacia abajo
  • Según el ABI System V AMD64, los argumentos se pasan en RDI, RSI, RDX, RCX, R8 y R9, y el valor de retorno en RAX
  • El modo usuario es ring 3, el kernel es ring 0, y las system calls e interrupciones cambian entre ambos mediante gates

Situaciones de error y diagnóstico

  • mmapEINVAL: error de alineación en el offset del archivo
  • mmapENOMEM: falta de espacio virtual o límite de overcommit
  • Acceso a un mapeo de archivo → SIGBUS: acceso más allá de EOF
  • mprotect(PROT_EXEC)EACCES: montaje noexec o política W^X
  • Aumento de RSS después de fork(): copia de páginas por CoW
  • Sobrescribir un mapeo existente con MAP_FIXED → se recomienda MAP_FIXED_NOREPLACE

Checklist práctico

  • Para asegurar memoria de inmediato: mmap + PROT_READ|PROT_WRITE + MAP_PRIVATE|MAP_ANONYMOUS
  • Al generar código: mantener W^X, usar mprotect(PROT_READ|PROT_EXEC)
  • Al mapear archivos: alinear offset a página, no acceder más allá de EOF
  • Si hay muchos page faults: usar MADV_WILLNEED o acceso anticipado
  • Para analizar uso de memoria: /proc/<pid>/smaps_rollup/proc/<pid>/maps
  • En fork de procesos grandes: considerar CoW y usar exec en el hijo
  • En entornos sensibles a la latencia: observar THP/mTHP, mlock y el comportamiento del TLB

Aún no hay comentarios.

Aún no hay comentarios.