El asesino OOM o Sin Memoria Asesino es un proceso que el
linux kernel emplea cuando el sistema tiene poca memoria. … Esto maximiza el uso de la memoria del sistema al garantizar que la
memoria asignada a los procesos se utilice activamente.
Esta pregunta auto respondida pregunta:
- ¿Cómo probar oom-killer desde la línea de comandos?
Se aceptaría un método más rápido que la media hora que se tarda en la auto-respuesta.
Respuesta aceptada:
La clave para activar el asesino OOM rápidamente es evitar atascarse con los accesos al disco. Entonces:
-
Evite el intercambio, a menos que su objetivo sea probar específicamente el comportamiento de OOM cuando se utiliza el intercambio. Puede deshabilitar el intercambio antes de la prueba y luego volver a habilitarlo.
swapon -s
le dice qué intercambios están habilitados actualmente.sudo swapoff -a
deshabilita todos los intercambios;sudo swapon -a
suele ser suficiente para volver a habilitarlos. -
Evite intercalar accesos a la memoria con accesos a discos que no sean de intercambio. Ese método basado en globbing finalmente usa su memoria disponible (dado que hay suficientes entradas en su sistema de archivos), pero la razón por la que necesita tanta memoria es para almacenar información que obtiene al acceder a su sistema de archivos. Incluso con un SSD, es probable que gran parte del tiempo se dedique a leer desde el disco, incluso si el intercambio está desactivado. Si su objetivo es probar específicamente el comportamiento de OOM para los accesos a la memoria que se intercalan con los accesos al disco, ese método es razonable, quizás incluso ideal. De lo contrario, puede lograr su objetivo mucho más rápido.
Una vez que haya deshabilitado el intercambio, cualquier método que rara vez lea desde un disco físico debería ser bastante rápido. Esto incluye el tail /dev/zero
(encontrado por falstaff, comentado arriba por Doug Smythies). Aunque lee desde el dispositivo de caracteres /dev/zero
, ese "dispositivo" solo genera bytes nulos (es decir, bytes de todos ceros) y no implica ningún acceso al disco físico una vez que se ha abierto el nodo del dispositivo. Ese método funciona porque tail
busca líneas finales en su entrada, pero una secuencia de ceros no contiene un carácter de nueva línea, por lo que nunca obtiene líneas para descartar.
Si está buscando una sola línea en un lenguaje interpretado que asigne y rellene la memoria algorítmicamente, está de suerte. En casi cualquier lenguaje interpretado de propósito general, es fácil asignar mucha memoria y escribir en ella sin usarla de otra manera. Aquí hay una frase de Perl que parece ser tan rápida como tail /dev/zero
(aunque no lo he evaluado ampliamente):
perl -wE 'my @xs; for (1..2**20) { push @xs, q{a} x 2**20 }; say scalar @xs;'
Con swap desactivado en una máquina antigua con 4 GiB de RAM, tanto eso como tail /dev/zero
tomó alrededor de diez segundos cada vez que los ejecuté. Ambos deberían funcionar bien en máquinas más nuevas con mucha más RAM que eso. Puedes hacer que perl
comando mucho más corto, si su objetivo es la brevedad.
Esa frase de Perl genera repetidamente (q{a} x 2**20
) separan cadenas moderadamente largas (alrededor de un millón de caracteres cada una) y las conservan almacenándolas en una matriz (@xs
). Puede ajustar los números para la prueba. Si no usa toda la memoria disponible, el one-liner genera el número total de cadenas creadas. Suponiendo que el asesino OOM mate a perl
–con el comando exacto que se muestra arriba y sin cuotas de recursos que se interpongan, creo que en la práctica siempre lo hará– entonces su shell debería mostrarle Killed
. Entonces, como en cualquier situación OOM, dmesg
tiene los detalles.
Aunque me gusta ese método, ilustra algo útil sobre escribir, compilar y usar un programa C, como el de la respuesta de Doug Smythies. La asignación de memoria y el acceso a la memoria no se sienten como cosas separadas en lenguajes interpretados de alto nivel, pero en C puede notar y, si lo desea, investigar esos detalles.
Finalmente, siempre debe verificar que el asesino OOM sea realmente lo que mató su programa . Una forma de verificar es inspeccionar dmesg
. Contrariamente a la creencia popular, en realidad es posible que un intento de asignar memoria falle rápidamente, incluso en Linux. Es fácil hacer que esto suceda con grandes asignaciones que obviamente fallarán... pero incluso esas pueden suceder inesperadamente. Y las asignaciones aparentemente razonables pueden fallar rápidamente. Por ejemplo, en mi máquina de prueba, perl -wE 'say length q{a} x 3_100_000_000;'
tiene éxito y perl -wE 'say length q{a} x 3_200_000_000;'
imprime:
Out of memory!
panic: fold_constants JMPENV_PUSH returned 2 at -e line 1.
Ninguno activó al asesino OOM. Hablando de manera más general:
- Si su programa precalcula cuánta memoria se necesita y la solicita en una sola asignación, la asignación puede tener éxito (y si lo hace, el eliminador de OOM puede o no eliminar el programa cuando se usa suficiente memoria), o la asignación simplemente puede fallar.
- Expandir una matriz a una longitud enorme al agregarle muchos, muchos elementos a menudo desencadena el asesino OOM en la práctica real, pero hacer que lo haga confiablemente en las pruebas es sorprendentemente complicado. La forma en que esto se hace casi siempre, porque es la forma más eficiente de hacerlo, es hacer que cada nuevo búfer tenga una capacidad x veces la capacidad del antiguo búfer. Valores comunes para x incluyen 1.5 y 2 (y la técnica a menudo se llama "duplicación de tablas"). Esto a veces cierra la brecha entre la cantidad de memoria que realmente se puede asignar y usar y la cantidad de memoria que el kernel sabe que es demasiado como para siquiera molestarse en pretender entregar.
- Las asignaciones de memoria pueden fallar por razones que tienen poco que ver con el kernel o con la cantidad de memoria disponible, y eso tampoco desencadena el asesino OOM. En particular, un programa puede fallar rápidamente en una asignación de cualquier tamaño después de realizar con éxito una gran cantidad de pequeñas asignaciones. Esta falla ocurre en la contabilidad que lleva a cabo el propio programa, generalmente a través de una biblioteca como
malloc()
. Sospecho que esto es lo que me pasó hoy cuando, durante la prueba conbash
matrices (que en realidad se implementan como listas doblemente enlazadas),bash
salir con un mensaje de error que dice una asignación de 9 bytes fallado.
El asesino OOM es mucho más fácil de activar accidentalmente que de forma intencionada.
Al intentar activar deliberadamente el asesino OOM, una forma de evitar estos problemas es comenzar solicitando demasiada memoria e ir gradualmente más pequeña, como lo hace el programa C de Doug Smythies. Otra forma es asignar un montón de fragmentos de memoria de tamaño moderado, que es lo que hace la frase de Perl que se muestra arriba:ninguna de las cadenas de caracteres millonarias (más un poco de uso de memoria adicional detrás de escena) es particularmente exigente, pero en conjunto, todas las compras de un megabyte se suman.