¿Cómo resolver este problema de memoria con gracia?

10

Tengo una computadora portátil estándar Linux (prueba Debian), con una partición de intercambio.

Hago muchos experimentos con eso. Algunos de ellos tienen mucha memoria y la forma en que Linux se comporta de manera predeterminada es un problema para mí ... Vamos a dar un ejemplo estúpido:

  1. Siéntate frente a la computadora portátil
  2. Abrir una terminal
  3. Escribe python, entoncesa = [0]*100000000

Ahora hay muchas posibilidades de que no tenga suficiente RAM para manejar esa gran lista. Linux llenará la RAM, luego el intercambio y, un par de minutos más tarde, el asesino OOM se activará y matará (casi) servicios aleatorios y, con suerte, si presiona Ctrl + C en el momento oportuno python, y si el terminal Todavía tenía el foco, la computadora volverá a responder.

Me gustaría imponer algunos límites de memoria para evitar ese intercambio no deseado y rechazar a un proceso el derecho de asignar más memoria de la que tengo (en RAM). Si la demanda de memoria está por debajo de un cierto límite o la raíz la solicita, simplemente elimine el proceso con más memoria de cualquier usuario, excepto la raíz.

ulimit -Sv [mem] Escucho en la parte de atrás!

Ho Ho! "Usar cgroupsvía cgexec!" alguien dice en la primera fila!

Sí, tiene razón: estas son realmente muy buenas soluciones. Pero:

  • No se aplican en todo el sistema.
  • Los límites se establecen por proceso
  • Los límites son estáticos, sin tener en cuenta la cantidad real de RAM libre (AFAIK)
  • Aquí y allá , dicen que no son realmente una buena solución para imponer límites duros.

Lo que me gustaría es que el núcleo diga: "Usted pertenece al usuario foo (no root), usa mucha memoria y nos quedaremos sin memoria. Lo siento amigo ... ¡muera ahora!"

O: "¿Qué demonios estás haciendo? Necesitas x MB y solo hay y MB disponibles. Sí, SWAP está vacío, pero no tienes la intención de usar el SWAP para hacer tu trabajo sucio, ¿verdad? No, yo ¡Dijo que no! ¡No te recuerdo! ¡Si insistes, morirás! "

Comunidad
fuente
2
Ya hay un algoritmo descrito en este artículo que ayuda al asesino de OOM a elegir el proceso correcto. El cambio /proc/sys/vm/overcommit_memoryafecta el comportamiento del kernel con poca memoria.
jofel
1
Sí, pero el overcommit_memoryarchivo especial usa RAM + SWAP como memoria utilizable. Todavía voy a cambiar :)
1
También debe explicar cómo esto no es un duplicado de esto: unix.stackexchange.com/questions/34334/… que contradice a sus grupos de WRT y usuarios individuales. PD. Si no desea intercambiar, desactive el intercambio .
Ricitos de oro
1
Quiero intercambiar! ¡Quiero hibernación, quiero que los bytes no utilizados se almacenen! Pero no quiero que los bytes usados se almacenen allí. Sobre el enlace, ulimitses una mala idea, como se muestra en casi todas partes, ya que es una limitación por proceso ... Lo sé :) cgroupsEsto definitivamente es mejor pero carece de algo más general: estoy hablando de mi computadora portátil, pero también posee un servidor de "cálculo" que somos tres para compartir. Si hago cumplir tales límites por usuario, estaré limitado por el peor de los casos, ¿no?
1
cgroups se aplica a cualquier proceso que decida: coloque todos los procesos de un usuario en un grupo separado y debe hacer lo que desee.
Peter

Respuestas:

4

Alguien sugirió en tu audiencia cgroups. Bueno, intente buscar esa dirección, ya que puede proporcionarle:

  • aplicado a un grupo de tareas que elija (por lo tanto, no en todo el sistema, pero tampoco por proceso)
  • los límites están establecidos para el grupo
  • los límites son estáticos
  • pueden imponer un límite estricto en la memoria y / o memoria + intercambio

Algo así podría acercarte a tus objetivos :

group limited {
  memory {
    memory.limit_in_bytes = 50M;
    memory.memsw.limit_in_bytes = 50M;
  }
}

Esto indica que las tareas en este cgroup pueden usar un máximo de 50M de memoria solamente y 50M de memoria + intercambio, por lo que cuando la memoria está llena, no se intercambiará, pero si la memoria no está llena y algunos datos podrían asignarse intercambio, esto podría permitirse.

Aquí hay un extracto de la documentación de memoria del cgroup :

Al usar memsw limit, puede evitar la OOM del sistema que puede ser causada por la escasez de intercambio.

Huygens
fuente
Todavía no es exactamente lo que esperaba. Pero la diferencia entre lo que espero y la realidad a menudo es bastante grande :) En este caso, quería estar seguro de que no me perdía nada como la overcommit_memoryvariable del núcleo. Gracias a todos.
0

Me encuentro con el mismo problema con frecuencia. Mi flujo de trabajo general implica un cálculo pesado en MATLAB. Ocasionalmente, intentaré asignar una variable nueva que exceda la cantidad de memoria disponible. El sistema se cuelga y, por lo general, tengo que reiniciar la máquina para volver al trabajo. :PAG

En mi caso, y también en el tuyo, no estaba tan preocupado por limitar la cantidad de memoria que MATLAB usa a una cantidad estática; estaba interesado en no tener una máquina congelada y estaba dispuesto a sacrificar mi proceso de MATLAB para preservar la capacidad de respuesta del sistema.

Inspirado por una respuesta a esta publicación , escribí el siguiente script (lo llamé watch_memory.sh):

#!/bin/bash

MONITOR=$(free | grep 'buffers/cache:')
MEM_USED=$(echo $MONITOR | awk '{ print $3 }')
MEM_FREE=$(echo $MONITOR | awk '{ print $4 }')

MEM_PERC=$(( 100*MEM_USED / (MEM_FREE+MEM_USED) ))

while :; do
    if [ "$MEM_PERC" -gt "95" ]
    then
        kill $1
        echo "$1 killed for using too much memory."
        exit
    fi
    sleep 1

    MONITOR=$(free | grep 'buffers/cache:')
    MEM_USED=$(echo $MONITOR | awk '{ print $3 }')
    MEM_FREE=$(echo $MONITOR | awk '{ print $4 }')
    MEM_PERC=$(( 100*MEM_USED / (MEM_FREE+MEM_USED) ))
done

Este script comprueba cada segundo la cantidad porcentual de memoria libre. Cuando el sistema se agota, su pid "chivo expiatorio" (aprobado como un argumento para el script) es asesinado.

Sin ajustar la prioridad (amabilidad) del guión, el chivo expiatorio tardó entre 10 y 20 segundos en morir, pero aún así funcionó. Ejecutar el script con una prioridad negativa resultó en una muerte instantánea después de la violación (11916 en este ejemplo es el pid que quiero matar si me quedo sin memoria):

sudo nice -n -5 bash watch_memory.sh 11916
Frijol gordon
fuente