Linux afina qué página de memoria expulsa primero: los parches MGLRU-FG

Cuando a un servidor se le acaba la memoria no se cae: empieza a elegir. El núcleo decide qué páginas saca de la RAM para hacer sitio, y de ese criterio depende que el sistema siga respondiendo o se arrastre. Durante décadas el algoritmo fue el mismo, el LRU: dos listas, una de páginas activas y otra de inactivas, y se expulsa por el final de la inactiva.

Ese esquema envejeció mal. Con cientos de gigabytes de RAM y miles de procesos, recorrer las listas sale caro y la distinción entre «activa» e «inactiva» es demasiado tosca. Por eso Linux incorporó en la versión 6.1 el MGLRU, Multi-Gen LRU: en lugar de dos listas hay varias generaciones, las páginas envejecen de una a otra y se expulsa siempre de la más vieja.

Lo que acaba de proponerse es el siguiente paso. Kairui Song, ingeniero de Tencent, envió el 3 de octubre a la lista de correo de gestión de memoria del kernel la tercera revisión de MGLRU-FG, diecisiete parches que cambian el criterio por el que una página sube de generación. En sus pruebas reporta «entre un 10 % y un 40 % más de rendimiento o menos refaults en distintas pruebas». Conviene decir cuanto antes que es una serie RFC: una propuesta para discutir, no algo que vaya a estar en tu servidor el mes que viene.

LRU clásico con dos listas frente a MGLRU con varias generacionesLas dos formas de decidir qué página de memoria se expulsa primeroLRU clásicodos listasactivainactivaal 2.º accesose expulsa del final de la inactivaMGLRUvarias generacionesgen 0la másviejagen 1gen 2gen 3la másjovenenvejecen hacia la izquierdase expulsa de aquíMGLRU ya está en el kernel desde la versión 6.1. Lo que cambia ahora es cómo se sube de generación

Claves de la propuesta

  • Qué significan las siglas: FG es frequency guided, promoción guiada por frecuencia. No es «fine-grained», un error que circula estos días.
  • Qué cambia: hoy una página sube de generación cuando se la toca; con FG sube en función de cuántas veces se la ha tocado. El núcleo deja de preguntarse «¿se ha usado?» para preguntarse «¿cuánto se usa?».
  • Quién y cuándo: Kairui Song, de Tencent, el 3 de octubre de 2026. Es la revisión 3 de una idea presentada en el congreso LSF/MM/BPF.
  • Tamaño: 17 parches, 21 archivos, 882 líneas añadidas y 526 eliminadas. El grueso está en mm/vmscan.c, el corazón de la recuperación de memoria.
  • Un efecto colateral bueno: gasta un bit menos de las banderas de página, que son un recurso escaso y muy disputado dentro del kernel.
  • Estado: RFC. El propio autor dice que lo mantiene así a propósito «porque es un cambio importante del LRU».

Qué hace distinto

La idea es contar. Cada página lleva ahora una cuenta de accesos, y esa cuenta determina a qué generación sube, con unos cuantos umbrales con nombre propio que fijan los parches:

La escala de accesos con la que MGLRU-FG promociona una páginaLo que añade FG: la página sube según cuántas veces se la ha tocado0recién leída1REFERENCED2WORKINGSET3PROTECTED…7MAXaccesos contados a la página → generación a la que subeMGLRU hoy gasta un bit más de las banderas de página para esto; FG lo hace con uno menos

Parece un detalle menor y no lo es, porque arregla un defecto conocido. En el MGLRU actual, una página leída por adelantado —lo que hace el sistema cuando detecta una lectura secuencial— entra con la cuenta a cero, en la generación más vieja, y que luego se use de verdad apenas la mueve. Una página leída al azar, en cambio, entra ya un escalón por encima. El resultado es que el núcleo protege lo aleatorio y sacrifica lo secuencial, aunque lo secuencial sea lo que más se está usando.

El propio autor señala que eso no es una decisión de diseño sino un accidente, y que depende de detalles de temporización interna. Con FG la cuenta de accesos es la que manda, venga la página de donde venga.

Los números, prueba por prueba

Song publica resultados de ocho bancos de pruebas distintos, en servidores de varias arquitecturas, equipos de escritorio y dos móviles Android. Estos son los que importan para un servidor.

Compilar el kernel bajo presión de memoria

Una compilación con 96 hilos dentro de un cgroup de 3 GB, usando ZRAM como espacio de intercambio. Es el caso que el titular describe como «presión de memoria»: cuadruplica el trabajo de recuperación respecto a la prueba de 48 hilos.

Compilación con 96 hilos, cgroup de 3 GB, intercambio en ZRAM. Media de 3-4 pasadas.
Medida MGLRU actual Con FG Diferencia
Tiempo real 1 m 54 s 1 m 45 s −9,5 s
Tiempo de sistema 72 m 12 s 57 m 10 s −21 %
Refaults de archivo 488 k 362 k −25,8 %
Páginas leídas de disco 111,3 M 100,0 M −10,1 %

El titular aquí no son los nueve segundos de reloj, sino los quince minutos de tiempo de CPU en modo núcleo que deja de gastarse. Eso es trabajo que la máquina estaba haciendo para moverse páginas a sí misma en vez de compilar.

Qué es un refault. Ocurre cuando el núcleo expulsa una página y, poco después, el programa vuelve a pedirla y hay que traerla otra vez. Es la medida directa de haberse equivocado al elegir. Bajar los refaults un 25 % significa que el sistema acierta bastante más en qué puede tirar.

Bases de datos y servicios

Cada prueba con su configuración; «LRU clásico» es el algoritmo anterior a MGLRU, incluido como referencia.
Prueba LRU clásico MGLRU actual Con FG
MongoDB YCSB, cgroup de 16 GB, 48 hilos (ops/s) 98 390 83 700 94 951 (+13,4 %)
Chromium y Node.js con ZRAM, 1 hora (peticiones) 63 822 132 763 233 774 (+76 %)
LevelDB scan/get (ops/s) 4 669 5 027 5 030
FIO con acceso zipf, cgroup de 16 GB (IOPS medias) — referencia +11,5 %

El caso más vistoso no está en esa tabla. Song reproduce el problema del acceso secuencial con dos programas corrientes: una base SQLite que relee una y otra vez una parte pequeña de un archivo, y un grep recorriendo muchos archivos que juntos no caben en RAM.

SQLite recorriendo y consultando una parte caliente, con grep machacando la caché en paralelo.
Algoritmo Consulta en SQLite Recorrido de grep
LRU clásico 14,51 ms 13 281 ms
MGLRU actual 567,05 ms 13 694 ms
Con FG 10,58 ms 12 930 ms

Esos 567 milisegundos frente a 14 son el defecto del que hablábamos: el MGLRU que hay hoy en el kernel es casi cuarenta veces más lento que el LRU clásico en ese patrón concreto. Con los parches no solo lo recupera, sino que queda por debajo de los dos.

Android, de propina

Song hizo también un portado informal a un Pixel 9 Pro con Android 17, lanzando y rotando 34 aplicaciones y 20 pestañas de Chrome hasta agotar la memoria en cada iteración, con unas dieciocho horas de pruebas en total. Los refaults de archivo bajan un 14 %, el intercambio un 12 % y las páginas leídas de disco un 18 %. En la prueba de fluidez, en cambio, no se midió ninguna diferencia perceptible.

Lo que no sale bien

Esta es la parte que la mayoría de los resúmenes se salta, y es la que decide si una serie de parches entra o no en el kernel. El autor la publica él mismo.

Hay una regresión. La misma compilación del kernel, pero intercambiando contra un SSD en vez de contra ZRAM, va doce segundos más lenta que el MGLRU actual, con un 9 % más de tiempo de sistema y un 17,5 % más de páginas escritas al intercambio. La explicación que da Song es que, al proteger mejor los archivos, el cgroup de 3 GB acaba empujando más memoria anónima fuera. Reconoce que la versión 3 «se ve más afectada por el exceso de recuperación de memoria anónima» que la anterior.

MongoDB sigue por detrás del LRU clásico. Mejora un 13,4 % respecto al MGLRU actual, pero se queda en 94 951 operaciones por segundo frente a las 98 390 del algoritmo antiguo. Es la única prueba en la que eso ocurre, y el autor lo atribuye a un umbral de escritura que habría que ajustar.

El 76 % de Chromium hay que cogerlo con pinzas. El propio Song avisa de que «algún cambio reciente parece haber roto la garantía de equidad de MGLRU» y ha hecho esa prueba muchísimo más rápida que hace unos meses, por motivos ajenos a esta serie.

Y falta una pieza. El trabajo no incluye todavía la distancia de refault, lo que significa que MGLRU puede tardar más en reaccionar cuando el conjunto de páginas en uso cambia de golpe. Song dice que se puede añadir después. Es exactamente el tipo de cabo suelto que hace que una serie siga en RFC.

Por qué importa

Importa porque el cuello de botella de los servidores se ha desplazado. Durante años la respuesta a un sistema lento era poner más RAM; hoy la memoria es cara —lo bastante como para que haya otra línea de trabajo en el mismo kernel reescribiendo la compresión de ZRAM por el mismo motivo— y la pregunta pasa a ser cuánto se puede exprimir la que ya hay. Un 20 % menos de tiempo de núcleo en una máquina bajo presión no es una cifra de laboratorio: es capacidad que se recupera sin comprar nada.

Importa también por dónde se nota. Las mejoras aparecen en contenedores con límite de memoria, que es como se ejecuta hoy prácticamente todo. Las pruebas de Song están hechas dentro de cgroups de 3 y 16 GB precisamente porque ahí es donde el algoritmo tiene que elegir de verdad; en una máquina con memoria de sobra, ninguno de estos números se mueve.

Y hay un detalle que dice bastante sobre cómo se escribe hoy el kernel: la serie lleva la etiqueta Assisted-by: LLM, con el autor explicando que usó un modelo de lenguaje para mejorar los comentarios y las pruebas. Es la misma convención que empezó a aparecer en los parches del kernel el mes pasado, y aquí se usa para lo que estaba pensada: declarar la ayuda sin esconderla y sin que sustituya a nadie.

Qué esperar

Nada inmediato. Una serie RFC de diecisiete parches que toca el corazón de la recuperación de memoria no entra en una ventana de integración sin varias rondas más de revisión, y el propio autor lo mantiene en RFC a conciencia. La regresión con intercambio en disco tendrá que resolverse o justificarse, y los nombres y umbrales pueden cambiar por el camino.

Lo que sí se puede dar por bueno es el diagnóstico. Que el MGLRU actual trata peor las lecturas secuenciales que las aleatorias no es una opinión: son 567 milisegundos contra 14 en una prueba que cualquiera puede reproducir con SQLite y grep. Se arregle con estos parches o con otros, ese problema está ahora documentado y medido, y eso ya es media reparación.

Sobre las cifras de este artículo. Todas salen de la carta de presentación de la propia serie de parches, leída en el archivo público de la lista linux-mm, no de resúmenes de terceros. Son mediciones del autor en su propio hardware y no han sido reproducidas de forma independiente; en una serie RFC eso es lo normal, y es parte de lo que la revisión del kernel sirve para comprobar.

Fuentes: «[PATCH RFC v3 00/17] mm/mglru: frequency guided promotion», de Kairui Song en la lista linux-mm (3 de octubre de 2026) y Phoronix, «MGLRU-FG Delivering Up To 10~40% Higher Performance For Linux In Some Tests».