¿Linux comenzará a matar mis procesos sin preguntarme si la memoria se acorta?


66

Estaba ejecutando un script de shell con comandos para ejecutar varios programas intensivos en memoria (2-5 GB) de forma consecutiva. Cuando volví a verificar el progreso de mi script, me sorprendió descubrir que algunos de mis procesos eran Killed, como me informó mi terminal. Varios programas ya se habían completado sucesivamente antes de los programas que se Killediniciaron más tarde , pero todos los programas luego fallaron en una falla de segmentación (que puede o no haber sido debido a un error en mi código, sigue leyendo).

Miré el historial de uso del clúster en particular que estaba usando y vi que alguien comenzó a ejecutar varios procesos intensivos en memoria al mismo tiempo y al hacerlo agotó la memoria real (y posiblemente incluso el espacio de intercambio) disponible para el clúster. Lo mejor que puedo imaginar, estos procesos intensivos en memoria comenzaron a ejecutarse casi al mismo tiempo que comencé a tener problemas con mis programas.

¿Es posible que Linux haya matado mis programas una vez que comenzó a quedarse sin memoria? ¿Y es posible que las fallas de segmentación que obtuve más tarde se debieran a la falta de memoria disponible para ejecutar mis programas (en lugar de un error en mi código)?


2
Cuando asigna memoria, ¿tiene una declaración para verificar si la memoria se asignó correctamente? Eso debería proporcionar una pista sobre si hay un error en su código o si se debió a una falta de memoria en el sistema.
unxnut

Respuestas:


72

Puede.

Hay dos condiciones diferentes de falta de memoria que puede encontrar en Linux. Lo que encuentre depende del valor de sysctl vm.overcommit_memory( /proc/sys/vm/overcommit_memory)

Introducción:
el núcleo puede realizar lo que se denomina "sobrecompromiso de memoria". Esto es cuando el núcleo asigna a los programas más memoria de la que realmente está presente en el sistema. Esto se hace con la esperanza de que los programas no usen toda la memoria que asignaron, ya que esto es algo bastante común.

overcommit_memory = 2

Cuando overcommit_memoryse establece en 2, el kernel no realiza ningún compromiso excesivo en absoluto. En cambio, cuando se asigna memoria a un programa, se garantiza el acceso para tener esa memoria. Si el sistema no tiene suficiente memoria libre para satisfacer una solicitud de asignación, el kernel simplemente devolverá un error para la solicitud. Depende del programa manejar con gracia la situación. Si no comprueba que la asignación se realizó correctamente cuando realmente falló, la aplicación a menudo encontrará una falla de seguridad.

En el caso de la segfault, debe encontrar una línea como esta en la salida de dmesg:

[1962.987529] myapp[3303]: segfault at 0 ip 00400559 sp 5bc7b1b0 error 6 in myapp[400000+1000]

Esto at 0significa que la aplicación intentó acceder a un puntero no inicializado, que puede ser el resultado de una llamada de asignación de memoria fallida (pero no es la única forma).

overcommit_memory = 0 y 1

Cuando overcommit_memoryse establece en 0o 1, se habilita el sobrecompromiso, y los programas pueden asignar más memoria de la que realmente está disponible.

Sin embargo, cuando un programa quiere usar la memoria que le fue asignada, pero el núcleo descubre que en realidad no tiene suficiente memoria para satisfacerlo, necesita recuperar algo de memoria. Primero intenta realizar varias tareas de limpieza de memoria, como vaciar cachés, pero si esto no es suficiente, terminará un proceso. Esta terminación es realizada por el OOM-Killer. El OOM-Killer observa el sistema para ver qué programas están usando qué memoria, cuánto tiempo han estado ejecutándose, quién los está ejecutando y una serie de otros factores para determinar cuál es el que se mata.

Después de que el proceso ha finalizado, la memoria que estaba usando se libera y el programa que acaba de causar la falta de memoria ahora tiene la memoria que necesita.

Sin embargo, incluso en este modo, a los programas todavía se les pueden denegar las solicitudes de asignación. Cuando overcommit_memoryes así 0, el kernel intenta adivinar cuándo debería comenzar a denegar las solicitudes de asignación. Cuando se establece en 1, no estoy seguro de qué determinación utiliza para determinar cuándo debe rechazar una solicitud, pero puede rechazar solicitudes muy grandes.

Puede ver si el OOM-Killer está involucrado mirando la salida de dmesgy encontrando mensajes como:

[11686.043641] Out of memory: Kill process 2603 (flasherav) score 761 or sacrifice child
[11686.043647] Killed process 2603 (flasherav) total-vm:1498536kB, anon-rss:721784kB, file-rss:4228kB

Entonces, parece que ambas situaciones me sucedieron.
NeutronStar

@Joshua Acabo de actualizar la respuesta. Olvidé mencionar que todavía puede obtener fallas de asignación cuando overcommit_memoryse establece en 0 o 2.
Patrick

Creo que valdría la pena editar un enlace a Taming the OOM killer en la publicación.
0xC0000022L

@ 0xC0000022L Gracias, es un buen artículo (aunque un poco desactualizado). No quería poner nada sobre el control del asesino OOM ya que eso no es parte de la pregunta (y no es un tema corto), y tenemos muchas otras preguntas aquí sobre eso.
Patrick

1
@mikeserv No digo que el comportamiento del asesino OOM no tenga nada que ver con controlarlo. La pregunta era si Linux mataría sus programas. Cómo evitar que Linux lo haga primero requiere establecer que efectivamente es Linux lo que hace. Y si overcommit_memory=2el asesino OOM ni siquiera está habilitado, entonces controlarlo es irrelevante. Sin embargo, una vez que establecemos que es el asesino de OOM, se convierte en otro tema que está cubierto por muchas otras preguntas y respuestas aquí.
Patrick

16

La verdad es que, independientemente de la forma en que lo mire, ya sea que su proceso se atascó debido al administrador de memoria del sistema o debido a algo más, sigue siendo un error. ¿Qué pasó con todos esos datos que acababas de procesar en la memoria? Debería haber sido guardado.

Si bien overcommit_memory=es la forma más general de configurar la administración OOM de Linux, también es ajustable por proceso como:

echo [-+][n] >/proc/$pid/oom_adj

El uso -17en lo anterior excluirá un proceso de la administración de falta de memoria. Probablemente no sea una gran idea en general, pero si está buscando errores, puede valer la pena, especialmente si desea saber si fue OOM o su código. Incrementar positivamente el número hará que el proceso sea más probable que se elimine en un evento OOM, lo que podría permitirle apuntalar mejor la capacidad de recuperación de su código en situaciones de poca memoria y garantizar que salga con gracia cuando sea necesario.

Puede verificar la configuración actual del controlador OOM por proceso como:

cat /proc/$pid/oom_score 

De lo contrario, podría suicidarse:

sysctl vm.panic_on_oom=1
sysctl kernel.panic=X

Eso configurará la computadora para reiniciar en caso de una condición de falta de memoria. Establece lo Xanterior en la cantidad de segundos que desea que la computadora se detenga después de un pánico del kernel antes de reiniciar. Enloquecer.

Y si, por alguna razón, decides que te gusta, hazlo persistente:

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf

Es un clúster compartido que estoy usando, estoy seguro de que los otros usuarios no apreciarían que se reiniciara sin su consentimiento.
NeutronStar

3
@Joshua: dudo mucho de que a alguien le guste, incluso desafía las leyes de robótica de Asimov. Por otro lado, como mencioné, también puede configurar el OOM por proceso de la otra manera. Es decir, puede clasificar personalmente en función de sus propios conjuntos de reglas definidos por proceso. Parece que ese tipo de cosas podría ser especialmente útil en un escenario de clúster compartido.
mikeserv
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.