Estou correndo pdftoppm
para converter um PDF fornecido pelo usuário em uma imagem 300DPI. Isso funciona muito bem, exceto se o usuário fornecer um PDF com um tamanho de página muito grande. pdftoppm
alocará memória suficiente para armazenar uma imagem de 300 DPI desse tamanho na memória, que para uma página quadrada de 100 polegadas é de 100 * 300 * 100 * 300 * 4 bytes por pixel = 3,5 GB. Um usuário mal-intencionado pode me fornecer um PDF bobo e causar todos os tipos de problemas.
Então, o que eu gostaria de fazer é colocar algum tipo de limite rígido no uso da memória para um processo filho que estou prestes a executar - basta interromper o processo se tentar alocar mais do que, digamos, 500 MB de memória. Isso é possível?
Não acho que o ulimit possa ser usado para isso, mas existe um equivalente de um processo?
docker
?Respostas:
Há alguns problemas com o ulimit. Aqui está uma leitura útil sobre o tópico: Limitando o tempo e o consumo de memória de um programa no Linux , que levam à ferramenta de tempo limite , que permite armazenar um processo (e seus garfos) pelo tempo ou pelo consumo de memória.
A ferramenta de tempo limite requer o Perl 5+ e o
/proc
sistema de arquivos montado. Depois disso, você copia a ferramenta para, por exemplo/usr/local/bin
:Depois disso, você pode 'engaiolar' seu processo pelo consumo de memória, como na sua pergunta da seguinte maneira:
Como alternativa, você pode usar
-t <seconds>
e,-x <hertz>
respectivamente, limitar o processo por tempo ou restrições de CPU.A maneira como essa ferramenta funciona é verificando várias vezes por segundo se o processo gerado não ultrapassou demais os limites definidos. Isso significa que na verdade existe uma pequena janela em que um processo pode estar com excesso de inscrições antes que o tempo limite seja notado e acabe com o processo.
Portanto, uma abordagem mais correta provavelmente envolveria cgroups, mas isso é muito mais complicado de configurar, mesmo se você usasse o Docker ou o runC, que, entre outras coisas, oferecem uma abstração mais amigável ao cgroups.
fonte
coreutils
utilitário padrão linux com o mesmo nome! Portanto, a resposta é potencialmente perigosa se, em qualquer lugar do seu sistema, algum pacote tiver um script que esperatimeout
ser ocoreutils
pacote padrão do linux ! Não conheço esta ferramenta sendo empacotada para distribuições como o debian.-t <seconds>
restrição mata o processo depois de tantos segundos?Outra maneira de limitar isso é usar os grupos de controle do Linux. Isso é especialmente útil se você deseja limitar a alocação de memória física de um processo (ou grupo de processos) distintamente da memória virtual. Por exemplo:
criará um grupo de controle chamado
myGroup
, limitará o conjunto de processos executados no myGroup até 500 MB de memória física e até 5000 MB de swap. Para executar um processo no grupo de controle:Observe que em uma distribuição moderna do Ubuntu, este exemplo requer a instalação do
cgroup-bin
pacote e a edição/etc/default/grub
para mudarGRUB_CMDLINE_LINUX_DEFAULT
para:e, em seguida, executando
sudo update-grub
e reiniciando para inicializar com os novos parâmetros de inicialização do kernel.fonte
firejail
programa também permitirá que você inicie um processo com limites de memória (usando cgroups e namespaces para limitar mais do que apenas memória). Nos meus sistemas, não precisei alterar a linha de comando do kernel para que isso funcionasse!GRUB_CMDLINE_LINUX_DEFAULT
modificação para tornar a configuração persistente? Eu encontrei outra maneira de torná-lo persistente aqui .swapaccount=1
GRUB_CMDLINE_LINUX_DEFAULT faz?Se o seu processo não gerar mais filhos que consomem mais memória, você poderá usar a
setrlimit
função Interface de usuário mais comum para isso é usar oulimit
comando do shell:Isso limitará apenas a memória "virtual" do seu processo, levando em consideração - e limitando - a memória que o processo que está sendo chamado compartilha com outros processos e a memória mapeada, mas não reservada (por exemplo, a grande pilha de Java). Ainda assim, a memória virtual é a aproximação mais próxima para processos que crescem muito, tornando os erros mencionados insignificantes.
Se o seu programa gera filhos, e são eles que alocam memória, ele se torna mais complexo e você deve escrever scripts auxiliares para executar processos sob seu controle. Eu escrevi no meu blog, por que e como .
fonte
setrlimit
mais complexo para mais crianças?man setrlimit
me diz que "Um processo filho criado através de fork (2) herda seus limites de recursos pais limites de recursos são preservados através execve (2)."ulimit
abordagem me ajudou comfirefox
o bug 622816 - Carregar uma imagem grande pode "congelar" o firefox ou travar o sistema ; que em uma inicialização USB (a partir da RAM) tende a congelar o sistema operacional, exigindo reinicialização forçada; agora pelo menosfirefox
trava, deixando o sistema operacional vivo ... Saúde!Estou usando o script abaixo, o que funciona muito bem.
Ele usa cgroups throughAtualização: agora usa os comandos decgmanager
.cgroup-tools
. Nomeie esse scriptlimitmem
e coloque-o no seu $ PATH e você poderá usá-lo comolimitmem 100M bash
. Isso limitará o uso de memória e troca. Para limitar apenas a memória, remova a linha commemory.memsw.limit_in_bytes
.edit: Nas instalações padrão do Linux, isso limita apenas o uso de memória, não o uso de swap. Para habilitar a limitação do uso de swap, você precisa habilitar a contabilidade de swap no seu sistema Linux. Fazer isso através da criação / adição
swapaccount=1
no/etc/default/grub
modo que parece algo comoEm seguida, execute
sudo update-grub
e reinicie.Disclaimer: Eu não ficaria surpreso se
cgroup-tools
também quebrar no futuro. A solução correta seria usar as APIs systemd para gerenciamento de cgroup, mas não há ferramentas de linha de comando para esse atmfonte
call to cgmanager_create_sync failed: invalid request
para cada processo que eu tento executarlimitmem 100M processname
. Estou no Xubuntu 16.04 LTS e esse pacote está instalado.$ limitmem 400M rstudio limiting memory to 400M (cgroup limitmem_24575) for command rstudio Error org.freedesktop.DBus.Error.InvalidArgs: invalid request
alguma ideia?percent
resultados for zero, oexpr
código de status será 1 e esse script será encerrado prematuramente. recomendamos alterar a linha para:percent=$(( "$peak_mem" / $(( "$bytes_limit" / 100 )) ))
(ref: unix.stackexchange.com/questions/63166/… )Além das ferramentas
daemontools
sugeridas por Mark Johnson, você também pode considerarchpst
quais são encontradas emrunit
. O próprio Runit está incluído no pacotebusybox
, portanto você já deve ter o instalado.A página do manual
chpst
mostra a opção:fonte
Estou executando o Ubuntu 18.04.2 LTS e o script JanKanis não funciona para mim como ele sugere. A execução
limitmem 100M script
está limitando 100 MB de RAM com troca ilimitada .A execução
limitmem 100M -s 100M script
falha silenciosamente, poiscgget -g "memory:$cgname"
não possui nenhum parâmetro chamadomemory.memsw.limit_in_bytes
.Então eu desabilitei o swap:
fonte
Em qualquer distribuição baseada em systemd, você também pode usar os cgroups indiretamente através do systemd-run. Por exemplo, para o seu caso de limitar
pdftoppm
a 500M de RAM, use:Nota: isso solicitará uma senha, mas o aplicativo será iniciado como seu usuário. Não permita que isso o iluda pensando que o comando precisa
sudo
, porque isso faria com que o comando fosse executado na raiz, o que dificilmente era sua intenção.Se você não quiser digitar a senha (afinal, como usuário você possui sua memória, por que você precisaria de uma senha para limitá-la) , você pode usar a
--user
opção; no entanto, para isso funcionar, você precisará do suporte ao cgroupsv2 ativado, o que agora requer a inicialização com osystemd.unified_cgroup_hierarchy
parâmetro kernel .fonte