Estoy corriendo pdftoppmpara 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. pdftoppmasignará 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
/procsistema 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
coreutilsutilidad 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 esperatimeoutser elcoreutilspaquete 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-binpaquete y editarlo/etc/default/grubpara cambiarloGRUB_CMDLINE_LINUX_DEFAULTa:y luego ejecutar
sudo update-gruby reiniciar para arrancar con los nuevos parámetros de arranque del kernel.fuente
firejailprograma 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_DEFAULTmodificación para que la configuración sea persistente? Encontré otra forma de hacerlo persistente aquí .swapaccount=1en GRUB_CMDLINE_LINUX_DEFAULT?Si su proceso no genera más hijos que consumen la mayor cantidad de memoria, puede usar la
setrlimitfunción. La interfaz de usuario más común para eso es usar elulimitcomando 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
setrlimitmás complejo para más niños?man setrlimitme 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)"ulimitenfoque me ayudó confirefoxel 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 sefirefoxbloquea, 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 scriptlimitmemy 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=1en/etc/default/grublo que se ve algo comoLuego corre
sudo update-gruby reinicia.Descargo de responsabilidad: no me sorprendería si
cgroup-toolstambié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 requestpara 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 requestalguna idea?percentresultados es cero, elexprcó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 considerarchpstcuá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
chpstmuestra 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 scriptes limitar 100 MB de RAM con intercambio ilimitado .La ejecución
limitmem 100M -s 100M scriptfalla 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
pdftoppma 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?) ,
--userPuede usar la opción, sin embargo, para que esto funcione, necesitará la compatibilidad con cgroupsv2 habilitada, ahora requiere arrancar con elsystemd.unified_cgroup_hierarchyparámetro del kernel .fuente