TL; DR
Corto temporal / respuesta
- Más fácil : tenga una partición de intercambio más pequeña y evite que el núcleo intente estar a la altura de la mentira de que no hay límite de memoria al ejecutar procesos desde un almacenamiento lento.
- Con un gran intercambio, el OOM (sin administrador de memoria) no toma medidas lo suficientemente pronto. Por lo general, cuenta de acuerdo con la memoria virtual y, en mi experiencia pasada, no mataba las cosas hasta que se completaba todo el intercambio, de ahí el sistema de rastreo y rastreo ...
- ¿Necesita un gran cambio para hibernar?
- Intento / problema : establezca algunos límites (p. Ej.
ulimit -v
, Verificar , y tal vez establezca un límite rígido o suave utilizando la as
opción en limits.conf
). Esto solía funcionar lo suficientemente bien, pero gracias a la presentación de WebKit gigacage
, muchas aplicaciones gnome ahora esperan espacios de direcciones ilimitados y no se pueden ejecutar.
- Intentaron / problemática : La política overcommit y la relación es otra manera de intentar gestionar y mitigar este (por ejemplo
sysctl vm.overcommit_memory
, sysctl vm.overcommit_ratio
pero este método no funcionó para mí.
- Difícil / complicado : intente aplicar una prioridad de cgroup a los procesos más importantes (por ejemplo, ssh), pero esto actualmente parece engorroso para cgroup v1 (con suerte v2 lo hará más fácil) ...
También encontré:
Solución a largo plazo
espere y espere que algunos parches ascendentes entren en núcleos de distribución estables. También esperamos que los proveedores de distribución optimicen mejor los valores predeterminados del kernel y aprovechen mejor los cgroups systemd para priorizar la capacidad de respuesta de la GUI en las ediciones de escritorio.
Algunos parches de interés:
Por lo tanto, no es solo un mal código de espacio de usuario y configuración de distribución / valores predeterminados lo que tiene la culpa: el kernel podría manejar esto mejor.
Comentarios sobre opciones ya consideradas
1) Deshabilitar el intercambio
Se recomienda proporcionar al menos una pequeña partición de intercambio ( ¿Realmente necesitamos intercambio en los sistemas modernos? ). Deshabilitar el intercambio no solo evita el intercambio de páginas no utilizadas, sino que también puede afectar la estrategia de sobrecompromiso heurística predeterminada del núcleo para asignar memoria ( ¿Qué significa la heurística en Overcommit_memory = 0? ), Ya que esa heurística cuenta con páginas de intercambio. Sin intercambio, el exceso de compromiso todavía puede funcionar en los modos heurístico (0) o siempre (1), pero la combinación de ningún intercambio y la estrategia de exceso de compromiso nunca (2) es probablemente una idea terrible. Por lo tanto, en la mayoría de los casos, es probable que ningún intercambio perjudique el rendimiento.
Por ejemplo, piense en un proceso de larga ejecución que inicialmente toca la memoria para el trabajo de una sola vez, pero luego no libera esa memoria y sigue ejecutando el fondo. El núcleo tendrá que usar RAM para eso hasta que finalice el proceso. Sin ningún intercambio, el kernel no puede localizarlo por otra cosa que realmente quiera usar RAM activamente. También piense en cuántos desarrolladores son perezosos y no liberan explícitamente memoria después del uso.
3) establecer una memoria máxima ulimit
¡Solo se aplica por proceso, y probablemente sea una suposición razonable que un proceso no debería solicitar más memoria de la que tiene físicamente un sistema! Por lo tanto, probablemente sea útil evitar que un proceso loco solitario desencadene una paliza mientras se establece generosamente.
4) mantenga programas importantes (X11, bash, kill, top, ...) en la memoria y nunca los cambie
Buena idea, pero esos programas acapararán la memoria que no están usando activamente. Puede ser aceptable si el programa solo solicita una cantidad modesta de memoria.
La versión systemd 232 acaba de agregar algunas opciones que hacen esto posible: creo que uno podría usar 'MemorySwapMax = 0' para evitar que una unidad (servicio) como ssh tenga algo de memoria intercambiada.
Sin embargo, ser capaz de priorizar el acceso a la memoria sería mejor.
Larga explicación
El kernel de Linux está más ajustado para las cargas de trabajo del servidor, por lo que la capacidad de respuesta de la GUI ha sido lamentablemente una preocupación secundaria ... La configuración de administración de memoria del kernel en la edición de escritorio de Ubuntu 16.04 LTS no parecía diferir de las otras ediciones del servidor. Incluso coincide con los valores predeterminados en RHEL / CentOS 7.2 que generalmente se usan como servidor.
OOM, limite e intercambie integridad por capacidad de respuesta
El intercambio de memoria (cuando el conjunto de memoria de trabajo, es decir, las páginas que se leen y escriben en un período de tiempo corto excede la RAM física) siempre bloqueará la E / S de almacenamiento; ninguna herramienta de kernel puede salvar un sistema de esto sin matar un proceso o dos...
Espero que los ajustes de OOM de Linux que se presenten en los núcleos más recientes reconozcan que este conjunto de trabajo excede la situación de la memoria física y mata un proceso. Cuando no es así, ocurre el problema de la paliza. El problema es que, con una gran partición de intercambio, puede parecer que el sistema todavía tiene espacio para la cabeza mientras que el núcleo se compromete alegremente y aún sirve solicitudes de memoria, pero el conjunto de trabajo podría desbordarse, tratando efectivamente de tratar el almacenamiento como si Es RAM.
En los servidores, acepta la penalización de rendimiento de la paliza por un determinado, lento, no perder datos, compensación. En las computadoras de escritorio, la compensación es diferente y los usuarios preferirían un poco de pérdida de datos (sacrificio de proceso) para mantener las cosas receptivas.
Esta fue una buena analogía cómica sobre OOM: oom_pardon, alias no mates mi xlock
Por cierto, OOMScoreAdjust
es otra opción del sistema para ayudar al peso y evitar los procesos de destrucción de OOM considerados más importantes.
reescritura amortiguada
Creo que " Hacer que la reescritura en segundo plano no sea mala " ayudará a evitar algunos problemas en los que un proceso que acapara la RAM provoca otro intercambio (escritura en el disco) y la escritura masiva en el disco detiene cualquier otra cosa que desee IO. No es la causa del problema, pero sí contribuye a la degradación general de la capacidad de respuesta.
limitación de ulimits
Un problema con ulimits es que el límite de contabilidad se aplica al espacio de direcciones de la memoria virtual (lo que implica combinar tanto el espacio físico como el de intercambio). Según man limits.conf
:
rss
maximum resident set size (KB) (Ignored in Linux 2.4.30 and
higher)
Por lo tanto, configurar un ulimit para que se aplique solo al uso de RAM física ya no parece útil. Por lo tanto
as
address space limit (KB)
parece ser el único sintonizable respetado.
Desafortunadamente, como se detalla más en el ejemplo de WebKit / Gnome, algunas aplicaciones no pueden ejecutarse si la asignación de espacio de direcciones virtuales es limitada.
cgroups debería ayudar en el futuro?
Actualmente, parece engorroso, pero es posible habilitar algunos indicadores de cgroup del núcleo cgroup_enable=memory swapaccount=1
(por ejemplo, en la configuración de grub) y luego intentar usar el controlador de memoria cgroup para limitar el uso de la memoria.
Los cgroups tienen características de límite de memoria más avanzadas que las opciones 'ulimit'. Las notas de CGroup v2 apuntan a intentos de mejorar el funcionamiento de ulimits.
La contabilidad y la limitación combinadas de memoria + intercambio se reemplazan por un control real sobre el espacio de intercambio.
Las opciones de CGroup se pueden configurar mediante las opciones de control de recursos systemd . P.ej:
Otras opciones útiles pueden ser
Estos tienen algunos inconvenientes:
- Gastos generales. La documentación actual de la ventana acoplable menciona brevemente el 1% de uso de memoria adicional y el 10% de degradación del rendimiento (probablemente con respecto a las operaciones de asignación de memoria, realmente no especifica).
- Las cosas de Cgroup / systemd se han reestructurado recientemente, por lo que el flujo ascendente implica que los proveedores de distribución de Linux podrían estar esperando que se solucione primero.
En CGroup v2 , sugieren que memory.high
debería ser una buena opción para regular y administrar el uso de memoria por parte de un grupo de procesos. Sin embargo, esta cita sugiere que monitorear las situaciones de presión de memoria necesitaba más trabajo (a partir de 2015).
Es necesaria una medida de la presión de la memoria (cuánto afecta la carga de trabajo debido a la falta de memoria) para determinar si una carga de trabajo necesita más memoria; desafortunadamente, el mecanismo de monitoreo de presión de memoria aún no está implementado.
Dado que las herramientas de espacio de usuario de systemd y cgroup son complejas, no he encontrado una manera simple de establecer algo apropiado y aprovechar esto aún más. La documentación de cgroup y systemd para Ubuntu no es excelente. El trabajo futuro debería ser para las distribuciones con ediciones de escritorio para aprovechar cgroups y systemd de modo que bajo una alta presión de memoria, ssh y los componentes de X-Server / window manager obtengan mayor prioridad de acceso a CPU, RAM física y IO de almacenamiento, para evitar competir con los procesos intercambio ocupado Las características de prioridad de CPU y E / S del núcleo han existido por un tiempo. Parece que falta acceso prioritario a la RAM física.
Sin embargo, ¡ni siquiera las prioridades de CPU e IO están configuradas adecuadamente! Cuando pude comprobar los límites de cgroup, cpu group, etc., aplicados, por lo que pude ver, Ubuntu no había hecho ninguna priorización predefinida. Por ejemplo, corrí:
systemctl show dev-mapper-Ubuntu\x2dswap.swap
Comparé eso con la misma salida para ssh, samba, gdm y nginx. Cosas importantes como la GUI y la consola de administración remota tienen que luchar por igual con todos los demás procesos cuando se produce la agitación.
Ejemplo de límites de memoria que tengo en un sistema de 16 GB de RAM
Quería habilitar la hibernación, así que necesitaba una gran partición de intercambio. Por lo tanto, intentar mitigar con ulimits, etc.
ulimit
Me puse * hard as 16777216
de /etc/security/limits.d/mem.conf
tal manera que ningún proceso único podría solicitar más memoria de la que es físicamente posible. No evitaré la agitación por completo, pero sin un solo proceso con uso de memoria codicioso, o una pérdida de memoria, puede provocar la agitación. Por ejemplo, he visto gnome-contacts
absorber 8GB + de memoria al hacer cosas mundanas como actualizar la lista global de direcciones desde un servidor de intercambio ...
Como se ve ulimit -S -v
, muchas distribuciones tienen este límite rígido y suave establecido como 'ilimitado' dado, en teoría, un proceso podría terminar solicitando mucha memoria pero solo usando activamente un subconjunto, y correr felizmente pensando que se le ha dado, por ejemplo, 24 GB de RAM mientras El sistema solo tiene 16GB. El límite rígido anterior causará que los procesos que pudieron ejecutarse correctamente se cancelen cuando el núcleo niega sus codiciosas solicitudes de memoria especulativa.
Sin embargo, también detecta cosas locas como contactos de gnomos y, en lugar de perder la capacidad de respuesta de mi escritorio, aparece el error "no hay suficiente memoria libre":
Complicaciones que configuran ulimit para el espacio de direcciones (memoria virtual)
Desafortunadamente, a algunos desarrolladores les gusta simular que la memoria virtual es un recurso infinito y establecer un límite en la memoria virtual puede dañar algunas aplicaciones. Por ejemplo, WebKit (del que dependen algunas aplicaciones de gnome) agregó una gigacage
característica de seguridad que intenta asignar cantidades increíbles de memoria virtual y ocurren FATAL: Could not allocate gigacage memory
errores con un toque descarado Make sure you have not set a virtual memory limit
. La solución,GIGACAGE_ENABLED=no
renuncia a los beneficios de seguridad, pero del mismo modo, no se permite limitar la asignación de memoria virtual también se renuncia a una característica de seguridad (por ejemplo, control de recursos que puede evitar la denegación de servicio). Irónicamente, entre los desarrolladores de gigacage y gnome, parecen olvidar que limitar la asignación de memoria es en sí mismo un control de seguridad. Y lamentablemente, noté que las aplicaciones gnome que dependen de gigacage no se molestan en solicitar explícitamente un límite superior, por lo que incluso un límite suave rompe las cosas en este caso.
Para ser justos, si el núcleo hizo un mejor trabajo al poder negar la asignación de memoria basada en el uso de la memoria residente en lugar de la memoria virtual, fingir que la memoria virtual es ilimitada sería menos peligroso.
exceso de compromiso
Si prefiere que se les niegue el acceso a la memoria a las aplicaciones y desea detener el exceso de compromiso, use los comandos a continuación para probar cómo se comporta su sistema cuando se encuentra bajo una presión de memoria alta.
En mi caso, la relación de compromiso predeterminada era:
$ sysctl vm.overcommit_ratio
vm.overcommit_ratio = 50
Pero solo entra en vigencia cuando se cambia la política para deshabilitar el exceso de compromiso y aplicar la proporción
sudo sysctl -w vm.overcommit_memory=2
La relación implicaba que solo se podían asignar 24GB de memoria en general (16GB RAM * 0.5 + 16GB SWAP). Por lo tanto, probablemente nunca vería aparecer OOM, y sería menos probable que los procesos accedan constantemente a la memoria en el intercambio. Pero también es probable que sacrifique la eficiencia general del sistema.
Esto provocará el bloqueo de muchas aplicaciones, dado que es común que los desarrolladores no manejen con gracia el sistema operativo que rechaza una solicitud de asignación de memoria. Cambia el riesgo ocasional de un bloqueo prolongado debido a la paliza (perder todo su trabajo después del restablecimiento completo) a un riesgo más frecuente de que varias aplicaciones se bloqueen. En mis pruebas, no ayudó mucho porque el escritorio se bloqueó cuando el sistema estaba bajo presión de memoria y no podía asignar memoria. Sin embargo, al menos las consolas y SSH todavía funcionaban.
Cómo funciona la memoria de sobrecompromiso de VM tiene más información.
Elegí volver al valor predeterminado para esto, sudo sysctl -w vm.overcommit_memory=0
dada la pila gráfica de escritorio completo y las aplicaciones en él se bloquean.