Linux no realiza "intercambios oportunistas" como se define en esta pregunta.
Las siguientes referencias principales no mencionan el concepto en absoluto:
- Comprensión del administrador de memoria virtual de Linux. Un libro en línea de Mel Gorman. Escrito en 2003, justo antes del lanzamiento de Linux 2.6.0.
- Documentación/admin-guide/sysctl/vm.rst. Esta es la documentación principal de la configuración ajustable de la administración de memoria virtual de Linux.
Más específicamente:
10.6 Demonio de salida de página (kswapd)
Históricamente kswapd
Solía activarse cada 10 segundos, pero ahora solo lo activa el asignador de páginas físicas cuando se alcanza el número de páginas libres en una zona. [...] Bajo una presión de memoria extrema, los procesos harán el trabajo de kswapd
sincrónicamente [...] kswapd
continúa liberando páginas hasta que se alcanza la marca de agua pages_high.
Según lo anterior, no esperaríamos ningún intercambio cuando el número de páginas gratuitas sea mayor que la "marca de agua máxima".
En segundo lugar, esto nos dice el propósito de kswapd
es hacer más páginas gratuitas.
Cuando kswapd
escribe una página de memoria para intercambiar, inmediatamente libera la página de memoria. kswapd no guarda una copia de la página intercambiada en la memoria .
Linux 2.6 usa el "rmap" para liberar la página. En Linux 2.4, la historia era más compleja. Cuando varios procesos compartían una página, kswapd no podía liberarla inmediatamente. Esta es la historia antigua. Todas las publicaciones vinculadas son sobre Linux 2.6 o superior.
intercambio
Este control se utiliza para definir la agresividad con la que el kernel intercambiará páginas de memoria. Los valores más altos aumentarán la agresividad, los valores más bajos disminuirán la cantidad de intercambio. Un valor de 0 le indica al kernel que no inicie el intercambio hasta que se agote la cantidad de páginas libres y respaldadas por archivos. es menor que la marca de agua alta en una zona.
Esta cita describe un caso especial:si configura el swappiness
valor para ser 0
. En este caso, tampoco deberíamos esperar ningún intercambio hasta que el número de páginas de caché haya caído al límite máximo. En otras palabras, el kernel intentará descartar casi todo el caché de archivos antes de comenzar a intercambiar. (Esto podría causar ralentizaciones masivas. ¡Necesita tener un caché de archivos! El caché de archivos se utiliza para almacenar el código de todos sus programas en ejecución :-)
¿Qué son las marcas de agua?
Las citas anteriores plantean la pregunta:¿Qué tan grandes son las reservas de memoria de "marca de agua" en mi sistema? Respuesta:en un sistema "pequeño", las marcas de agua de zona predeterminadas pueden llegar al 3% de la memoria. Esto se debe al cálculo de la marca de agua "mín". En sistemas más grandes, las marcas de agua serán una proporción más pequeña, acercándose al 0,3 % de la memoria.
Entonces, si la pregunta es sobre un sistema con más del 10 % de memoria libre, los detalles exactos de esta lógica de marca de agua no son significativos.
Las marcas de agua para cada "zona" individual se muestran en /proc/zoneinfo
, como se documenta en proc(5). Un extracto de mi zoneinfo:
Node 0, zone DMA32
pages free 304988
min 7250
low 9062
high 10874
spanned 1044480
present 888973
managed 872457
protection: (0, 0, 4424, 4424, 4424)
...
Node 0, zone Normal
pages free 11977
min 9611
low 12013
high 14415
spanned 1173504
present 1173504
managed 1134236
protection: (0, 0, 0, 0, 0)
Las "marcas de agua" actuales son min
, low
y high
. Si un programa alguna vez solicita suficiente memoria para reducir free
debajo de min
, el programa entra en "reclamación directa". El programa está hecho para esperar mientras el kernel libera memoria.
Queremos evitar la reclamación directa si es posible. Así que si free
caería por debajo del low
marca de agua, el núcleo activa kswapd
. kswapd
libera memoria intercambiando y/o eliminando cachés, hasta free
está por encima de high
de nuevo.
Cualificación adicional:kswapd
también se ejecutará para proteger la cantidad completa de lowmem_reserve, para el uso de kernel lowmem y DMA. El lowmem_reserve predeterminado es aproximadamente 1/256 de los primeros 4 GiB de RAM (zona DMA32), por lo que suele rondar los 16 MiB.
Confirmaciones de código Linux
mm:escala kswapd marcas de agua en proporción a la memoria
[...]
marca_de_agua_factor_de_escala:
Este factor controla la agresividad de kswapd. Define la cantidad de memoria que queda en un nodo/sistema antes de que kswapd se despierte y cuánta memoria debe estar libre antes de que kswapd vuelva a dormir.
La unidad está en fracciones de 10.000. El valor predeterminado de 10 significa que las distancias entre las marcas de agua son el 0,1 % de la memoria disponible en el nodo/sistema. El valor máximo es 1000, o el 10 % de la memoria.
Una alta tasa de subprocesos que ingresan a la reclamación directa (allocstall) o que kswapd se va a dormir prematuramente (kswapd_low_wmark_hit_quickly) puede indicar que la cantidad de páginas libres que kswapd mantiene por razones de latencia es demasiado pequeña para las ráfagas de asignación que ocurren en el sistema. Esta perilla se puede usar para ajustar la agresividad de kswapd en consecuencia.
proc:meminfo:calcule la memoria disponible de forma más conservadora
El MemAvailable
artículo en /proc/meminfo
es dar a los usuarios una pista de cuánta memoria se puede asignar sin causar un intercambio, por lo que excluye las marcas de agua bajas de las zonas como no disponibles para el espacio del usuario.
Sin embargo, para una asignación de espacio de usuario, kswapd
en realidad reclamará hasta que las páginas gratuitas alcancen una combinación de la marca de agua alta y la protección de memoria baja del asignador de páginas que también mantiene una cierta cantidad de memoria DMA y DMA32 del espacio del usuario.
Resta la cantidad total que sabemos que no está disponible para el espacio de usuario de la cantidad de páginas libres al calcular MemAvailable.
Código Linux
A veces se afirma que cambiar swappiness
a 0
deshabilitará efectivamente el "intercambio oportunista". Esto proporciona una interesante vía de investigación. Si hay algo llamado "intercambio oportunista", y se puede ajustar mediante swappiness, entonces podríamos perseguirlo encontrando todas las cadenas de llamadas que dicen vm_swappiness
. Tenga en cuenta que podemos reducir nuestro espacio de búsqueda asumiendo CONFIG_MEMCG
no está configurado (es decir, los "cgroups de memoria" están deshabilitados). La cadena de llamadas va:
- vm_swappiness
- mem_cgroup_swappiness
- get_scan_count
- shrink_node_memcg
- shrink_nodo
shrink_node_memcg
se comenta "Esta es una página básica por nodo más libre. Utilizada tanto por kswapd como por reclamo directo". Es decir. esta función aumenta el número de gratis paginas No está tratando de duplicar páginas para intercambiar para que puedan liberarse mucho más tarde. Pero incluso si descontamos eso:
La cadena anterior se llama desde tres funciones diferentes, que se muestran a continuación. Como era de esperar, podemos dividir los sitios de llamada en reclamo directo vs. kswapd. No tendría sentido realizar un "intercambio oportunista" en la recuperación directa.
/* * This is the direct reclaim path, for page-allocating processes. We only * try to reclaim pages from zones which will satisfy the caller's allocation * request. * * If a zone is deemed to be full of pinned pages then just give it a light * scan then give up on it. */ static void shrink_zones
* kswapd shrinks a node of pages that are at or below the highest usable * zone that is currently unbalanced. * * Returns true if kswapd scanned at least the requested number of pages to * reclaim or if the lack of progress was due to pages under writeback. * This is used to determine if the scanning priority needs to be raised. */ static bool kswapd_shrink_node
* For kswapd, balance_pgdat() will reclaim pages across a node from zones * that are eligible for use by the caller until at least one zone is * balanced. * * Returns the order kswapd finished reclaiming at. * * kswapd scans the zones in the highmem->normal->dma direction. It skips * zones which have free_pages > high_wmark_pages(zone), but once a zone is * found to have free_pages <= high_wmark_pages(zone), any page in that zone * or lower is eligible for reclaim until at least one usable zone is * balanced. */ static int balance_pgdat
Entonces, presumiblemente, la afirmación es que kswapd se activa de alguna manera, incluso cuando todas las asignaciones de memoria se satisfacen inmediatamente desde la memoria libre. Revisé los usos de wake_up_interruptible(&pgdat->kswapd_wait)
, y no veo ningún despertar como este.
No, no existe el intercambio oportunista en Linux. Pasé un tiempo analizando el problema y todas las fuentes (libros de texto, correos electrónicos en las listas de correo de los desarrolladores del kernel, código fuente de Linux y comentarios de confirmación, y algunos intercambios de Twitter con Mel Gorman) me dicen lo mismo:Linux solo reclama memoria en respuesta a alguna forma de presión de la memoria (con la obvia excepción de la hibernación).
Todos los conceptos erróneos populares sobre el tema probablemente se derivan del simple hecho de que Linux no puede darse el lujo de esperar hasta el último byte de memoria libre antes de comenzar el intercambio. Necesita algún tipo de colchón para protegerlo de formas extremas de agotamiento de la memoria, y hay algunos ajustes que pueden afectar el tamaño de ese colchón (por ejemplo, vm.min_free_kbytes
). Pero no es lo mismo que "cambiar porque no hay nada mejor que hacer".
Desafortunadamente, el algoritmo de recuperación de marcos de página se ha vuelto mucho más complejo con respecto a 2.6 (cuando se describió en detalle en el libro de Mel Gorman), pero la idea básica es más o menos la misma:la recuperación de página se desencadena por asignaciones fallidas, que luego despierta kswapd
o intente liberar páginas sincrónicamente (según la presión de la memoria, los indicadores de asignación y otros factores).
La razón más obvia por la que las asignaciones de páginas pueden comenzar a fallar con suficiente memoria libre es que pueden estar solicitando memoria contigua cuando en realidad la memoria puede estar demasiado fragmentada para satisfacer la solicitud. Históricamente, los desarrolladores del kernel de Linux hicieron todo lo posible para evitar la necesidad de asignaciones contiguas. Sin embargo, algunos controladores de dispositivos todavía requieren eso, ya sea porque no pueden hacer E/S de memoria de varias páginas (DMA de dispersión y recopilación), o porque los desarrolladores de controladores pueden codificar de manera descuidada. La llegada de Transparent Huge Pages (THP) proporcionó otra razón para asignar memoria en fragmentos físicamente contiguos.
Se supone que la compactación de zonas, que se introdujo aproximadamente al mismo tiempo, ayuda con el problema de fragmentación de la memoria, pero no siempre produce el efecto esperado.
Hay varios vmscan
puntos de rastreo que pueden ayudar a comprender qué está pasando exactamente en su caso específico:siempre es más fácil encontrar lo que necesita en el código del kernel de Linux cuando tiene pilas de llamadas específicas, en lugar de simplemente escanear todo lo que parece remotamente relevante.