¿Cómo puedo limitar la cantidad de memoria disponible para un proceso?

11

Estoy desarrollando un programa en marcha; ocasionalmente termina asignando grandes cantidades de memoria (>> 10G en una máquina con 8G de memoria física), lo que hace que el sistema deje de responder. Quiero limitar la cantidad de memoria que el proceso puede asignar. La forma habitual en que haría esto es:

ulimit -m 4000000 ; ./myprogram

... que debería matar mi programa si intenta usar más de 4 GB de memoria.

En OS X El Capitan esto parece no tener efecto; incluso ulimit -m 1(¡limitar todos los programas a solo 1kB de memoria!) es ineficaz.

¿Cómo puedo establecer un límite superior en la memoria disponible para un proceso en particular?

cpcallen
fuente
Cuando dices De la manera habitual que haría esto , ¿qué quieres decir? Más específicamente, ¿ cuándo sueles hacer esto? Y cuando lo haces, ¿te refieres a Mac OS X El Capitan o en otro entorno? ¿Puedes dar un ejemplo de cuándo lo has usado con éxito? Básicamente, solo estoy tratando de aclarar si este proceso funciona para usted normalmente, ¿pero no funciona para este programa en particular? ¿O no está funcionando para ti pero crees que debería?
Monomeeth
1
Por "la forma habitual en que haría esto", me refiero a la forma en que haría esto en otros sabores de Unix. Observo que acabo de descubrir que ulimit -mya no funciona en Linux (> 2.4.30), aunque ulimit -vtodavía funciona como se esperaba. (Como ulimit -m, ulimit -vtambién parece no tener efecto en OS X.)
cpcallen
Parece que tiene una pérdida de memoria en el programa que está escribiendo y necesita mejorar la recolección de basura. ¿Has leído sobre la gestión de memoria en marcha?
Todd Dabney
1
No, no es una pérdida de memoria, solo una búsqueda gráfica de un espacio de estado potencialmente muy grande. Podría agregar código para abortar la búsqueda si las diversas estructuras internas se vuelven demasiado grandes, pero esperaba poder hacer lo mismo (evitar que la máquina se atasque con entradas grandes) con un shell de una sola línea.
cpcallen

Respuestas:

1

Hay dos enfoques para limitar el uso de la memoria: ex post facto y preventivo. Es decir, puede intentar matar su programa después de que se haya vuelto demasiado grande, o puede programarlo para que no sea demasiado grande en primer lugar.

Si insiste en el enfoque ex post facto, puede usar el siguiente script de Bash. Este script primero encuentra la cantidad de memoria (como se define por "tamaño de conjunto residente") que el proceso con processid pid está usando, filtra todos los datos no numéricos usando grep y guarda la cantidad como variable n. El script luego comprueba si n es mayor que su x especificado. Si es así, el proceso con procesid pid se elimina.

Tenga en cuenta:

  1. Debe reemplazar <pid>con la identificación del proceso de su programa.
  2. Debe reemplazar <x>con rss = "tamaño de conjunto residente" (es decir, tamaño de memoria real) que no desea que exceda el programa.

n=$(ps -<pid> -o rss | grep '[0-9]') if [ $n -gt <x> ]; then kill -9 <pid>; fi

Si desea que esto se ejecute cada y segundos, inclúyalo en un bucle y dígale que espere y segundos después de cada iteración. También podría escribir un comando similar usando top. Tu punto de partida sería top -l 1|grep "<pid>"|awk '{print $10}'.

La respuesta de @Kenorb me ayudó con mi guión


Si bien creo que eso responde a la pregunta, a la larga creo que es un mejor diseño de programación adoptar un enfoque preventivo utilizando la asignación manual de memoria.

En primer lugar, ¿estás seguro de que el uso de memoria es realmente un problema? La documentación de Go dice:

El asignador de memoria Go reserva una gran región de memoria virtual como escenario de asignaciones. Esta memoria virtual es local para el proceso específico de Go; La reserva no priva a otros procesos de memoria.

Si aún cree que tiene un problema, le recomiendo que administre manualmente su memoria como se hace en el lenguaje de programación C. Como go está escrito en C, sospeché que habría formas de ingresar a la administración / asignaciones de memoria C, y de hecho las hay. Vea este repositorio de github que,

le permite administrar manualmente la memoria a través del asignador estándar de C para su sistema. Es una envoltura delgada sobre malloc, calloc y sin. Consulte man malloc para obtener detalles sobre estas funciones para su sistema. Esta biblioteca usa cgo.

El caso de uso se da como:

Por qué querrías esto?

Cuando un programa está causando presión en la memoria o el sistema se está quedando sin memoria, puede ser útil controlar manualmente las asignaciones y desasignaciones de memoria. Go puede ayudarlo a controlar las asignaciones, pero no es posible desasignar explícitamente datos innecesarios.

Esto parece una mejor solución a largo plazo.

Si desea obtener más información sobre C (incluida la administración de memoria), el lenguaje de programación C es la referencia estándar.

Evan Rosica
fuente
Estoy seguro de que el uso de memoria es realmente un problema. Cuando el programa creció inesperadamente a un tamaño de memoria física> 2x, la máquina dejó de responder casi por completo debido a la agitación de la página. Pasó aproximadamente una hora entre cuando presioné ^ C y cuando macOS continuó respondiendo a los clics del mouse; Mientras tanto, la única evidencia de que no estaba congelado era el ruido silencioso del disco duro que se movía rápidamente.
cpcallen
Esta es probablemente una solución razonable en la práctica, pero a diferencia de ulimit en sistemas operativos UNIX (no Darwin), depende de poder asignar suficiente memoria de manera oportuna para ejecutar con éxito el comando kill. Realmente prefiero que el núcleo imponga límites de tamaño de proceso.
cpcallen
@cpcallen haciendo algunas búsquedas, parece que el "parámetro -m para ulimit no tiene ningún efecto en los sistemas Linux con versiones de kernel más recientes que 2.4.30". Parece que OSX también se ha dado cuenta de este cambio. Pruebe la opción -v para limitar el espacio de direcciones
Evan Rosica