Estoy corriendo pdftoppm
para convertir un PDF proporcionado por el usuario en una imagen de 300 DPI. Esto funciona muy bien, excepto si el usuario proporciona un PDF con un tamaño de página muy grande. pdftoppm
asignará suficiente memoria para contener una imagen de 300 DPI de ese tamaño en la memoria, que para una página cuadrada de 100 pulgadas es 100 * 300 * 100 * 300 * 4 bytes por píxel = 3.5GB. Un usuario malintencionado podría darme un PDF tonto y grande y causar todo tipo de problemas.
Entonces, lo que me gustaría hacer es poner algún tipo de límite estricto en el uso de memoria para un proceso secundario que estoy a punto de ejecutar; solo haga que el proceso muera si intenta asignar más de, digamos, 500 MB de memoria. ¿Es eso posible?
No creo que se pueda usar ulimit para esto, pero ¿hay un equivalente de un proceso?
docker
?Respuestas:
Hay algunos problemas con ulimit. Aquí hay una lectura útil sobre el tema: Limitar el tiempo y el consumo de memoria de un programa en Linux , lo que lleva a la herramienta de tiempo de espera , que le permite enjaular un proceso (y sus tenedores) por tiempo o consumo de memoria.
La herramienta de tiempo de espera requiere Perl 5+ y el
/proc
sistema de archivos montado. Después de eso, copie la herramienta para, p. Ej/usr/local/bin
.Después de eso, puede 'enjaular' su proceso por consumo de memoria como en su pregunta de esta manera:
Alternativamente, podría usar
-t <seconds>
y-x <hertz>
para limitar el proceso respectivamente por tiempo o restricciones de CPU.La forma en que funciona esta herramienta es verificando varias veces por segundo si el proceso generado no ha suscrito en exceso sus límites establecidos. Esto significa que en realidad hay una pequeña ventana en la que un proceso podría estar suscribiéndose en exceso antes de que el tiempo de espera se dé cuenta y mate el proceso.
Por lo tanto, un enfoque más correcto probablemente involucraría a cgroups, pero eso es mucho más complicado de configurar, incluso si usa Docker o runC, que entre otras cosas, ofrece una abstracción más fácil de usar en torno a cgroups.
fuente
coreutils
utilidad estándar de Linux del mismo nombre. Por lo tanto, la respuesta es potencialmente peligrosa si en algún lugar de su sistema, ¡algún paquete tiene un script que esperatimeout
ser elcoreutils
paquete estándar de Linux ! No tengo conocimiento de que esta herramienta esté empaquetada para distribuciones como debian.-t <seconds>
restricción mata el proceso después de tantos segundos?Otra forma de limitar esto es usar los grupos de control de Linux. Esto es especialmente útil si desea limitar la asignación de memoria física de un proceso (o grupo de procesos) de forma distinta a la memoria virtual. Por ejemplo:
creará un grupo de control llamado
myGroup
, limitará el conjunto de procesos ejecutados bajo myGroup hasta 500 MB de memoria física y hasta 5000 MB de intercambio. Para ejecutar un proceso bajo el grupo de control:Tenga en cuenta que en una distribución moderna de Ubuntu, este ejemplo requiere instalar el
cgroup-bin
paquete y editarlo/etc/default/grub
para cambiarloGRUB_CMDLINE_LINUX_DEFAULT
a:y luego ejecutar
sudo update-grub
y reiniciar para arrancar con los nuevos parámetros de arranque del kernel.fuente
firejail
programa también le permitirá iniciar un proceso con límites de memoria (utilizando cgroups y espacios de nombres para limitar más que solo la memoria). ¡En mis sistemas no tuve que cambiar la línea de comando del núcleo para que esto funcione!GRUB_CMDLINE_LINUX_DEFAULT
modificación para que la configuración sea persistente? Encontré otra forma de hacerlo persistente aquí .swapaccount=1
en GRUB_CMDLINE_LINUX_DEFAULT?Si su proceso no genera más hijos que consumen la mayor cantidad de memoria, puede usar la
setrlimit
función. La interfaz de usuario más común para eso es usar elulimit
comando del shell:Esto solo limitará la memoria "virtual" de su proceso, teniendo en cuenta, y limitando, la memoria que el proceso que se invoca comparte con otros procesos, y la memoria asignada pero no reservada (por ejemplo, el gran montón de Java). Aún así, la memoria virtual es la aproximación más cercana para procesos que crecen realmente grandes, haciendo que dichos errores sean insignificantes.
Si su programa genera hijos, y son ellos los que asignan memoria, se vuelve más complejo, y debe escribir scripts auxiliares para ejecutar procesos bajo su control. Escribí en mi blog, por qué y cómo .
fuente
setrlimit
más complejo para más niños?man setrlimit
me dice que "Un proceso hijo creado mediante fork (2) hereda los límites de recursos de sus padres. Los límites de recursos se conservan en execve (2)"ulimit
enfoque me ayudó confirefox
el error 622816: cargar una imagen grande puede "congelar" Firefox o bloquear el sistema ; que en un arranque USB (desde RAM) tiende a congelar el sistema operativo, lo que requiere un reinicio completo; ahora al menos sefirefox
bloquea, dejando vivo el sistema operativo ... ¡Salud!Estoy usando el siguiente script, que funciona muy bien.
Utiliza cgroups a través deActualización: ahora utiliza los comandos decgmanager
.cgroup-tools
. Nombra este scriptlimitmem
y ponlo en tu $ PATH y puedes usarlo comolimitmem 100M bash
. Esto limitará el uso de memoria y de intercambio. Para limitar solo la memoria, elimine la línea conmemory.memsw.limit_in_bytes
.editar: en las instalaciones de Linux predeterminadas, esto solo limita el uso de memoria, no el uso de intercambio. Para habilitar la limitación de uso de intercambio, debe habilitar la contabilidad de intercambio en su sistema Linux. Hacer que al establecer / adición
swapaccount=1
en/etc/default/grub
lo que se ve algo comoLuego corre
sudo update-grub
y reinicia.Descargo de responsabilidad: no me sorprendería si
cgroup-tools
también se rompe en el futuro. La solución correcta sería usar la API de systemd para la administración de cgroup, pero no hay herramientas de línea de comandos para ese cajero automáticofuente
call to cgmanager_create_sync failed: invalid request
para cada proceso que intento ejecutarlimitmem 100M processname
. Estoy en Xubuntu 16.04 LTS y ese paquete está instalado.$ limitmem 400M rstudio limiting memory to 400M (cgroup limitmem_24575) for command rstudio Error org.freedesktop.DBus.Error.InvalidArgs: invalid request
alguna idea?percent
resultados es cero, elexpr
código de estado es 1 y este script se cierra prematuramente. recomiendo cambiar la línea a:percent=$(( "$peak_mem" / $(( "$bytes_limit" / 100 )) ))
(ref: unix.stackexchange.com/questions/63166/… )Además de las herramientas de
daemontools
, sugeridas por Mark Johnson, también puede considerarchpst
cuál se encuentra enrunit
. Runit en sí está incluidobusybox
, por lo que es posible que ya lo tenga instalado.La página de manual de
chpst
muestra la opción:fuente
Estoy ejecutando Ubuntu 18.04.2 LTS y el script JanKanis no funciona para mí como él sugiere. Correr
limitmem 100M script
es limitar 100 MB de RAM con intercambio ilimitado .La ejecución
limitmem 100M -s 100M script
falla en silencio ya quecgget -g "memory:$cgname"
no tiene ningún parámetro nombradomemory.memsw.limit_in_bytes
.Entonces deshabilité el intercambio:
fuente
En cualquier distribución basada en systemd, también puede usar cgroups indirectamente a través de systemd-run. Por ejemplo, para su caso de limitación
pdftoppm
a 500M de RAM, use:Nota: esto te pedirá una contraseña, pero la aplicación se iniciará como tu usuario. No permita que esto lo engañe y piense que el comando lo necesita
sudo
, porque eso haría que el comando se ejecute bajo la raíz, lo que difícilmente era su intención.Si no desea ingresar la contraseña (después de todo, como usuario posee su memoria, ¿por qué necesitaría una contraseña para limitarla?) ,
--user
Puede usar la opción, sin embargo, para que esto funcione, necesitará la compatibilidad con cgroupsv2 habilitada, ahora requiere arrancar con elsystemd.unified_cgroup_hierarchy
parámetro del kernel .fuente