Quero fazer alguns testes com poucos recursos e para isso preciso ter 90% da memória livre cheia.
Como posso fazer isso em um *nix
sistema?
Quero fazer alguns testes com poucos recursos e para isso preciso ter 90% da memória livre cheia.
Como posso fazer isso em um *nix
sistema?
Respostas:
stress-ng é um gerador de carga de trabalho que simula o estresse da cpu / mem / io / hdd nos sistemas POSIX. Essa chamada deve funcionar no Linux <3.14:
stress-ng --vm-bytes $(awk '/MemFree/{printf "%d\n", $2 * 0.9;}' < /proc/meminfo)k --vm-keep -m 1
Para Linux> = 3.14, você pode usar MemAvailable
para estimar a memória disponível para novos processos sem trocar:
stress-ng --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 * 0.9;}' < /proc/meminfo)k --vm-keep -m 1
Adapte a /proc/meminfo
chamada com free(1)
/ vm_stat(1)
/ etc. se você precisar dele portátil.
stress --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 * 0.98;}' < /proc/meminfo)k --vm-keep -m 1
--vm 1 and --vm-keep
é muito importante. Simplesmente --vm-bytes
não faz nada e você pode ser enganado ao pensar que pode alocar a quantidade de memória que precisa / deseja. Fiquei pouco com isso até que tentei verificar minha sanidade, alocando 256G de memória. Esta não é uma falha na resposta, fornece as sinalizações corretas, apenas um cuidado adicional.
-m 1
. De acordo com a página de manual do estresse, -m N
é a abreviação de --vm N
: spawn N
workers spinning onmalloc()/free()
Você pode gravar um programa C malloc()
na memória necessária e depois usá-lo mlock()
para impedir que a memória seja trocada.
Em seguida, deixe o programa aguardar a entrada do teclado e desbloqueie a memória, libere a memória e saia.
calloc
vai correr para o mesmo problema IIRC. Toda a memória apontará apenas para a mesma página zerada somente leitura. Na verdade, ele não será alocado até que você tente gravá-lo (o que não funcionará, pois é somente leitura). A única maneira de ter certeza de que sei é fazer um memset
buffer inteiro. Veja a resposta a seguir para obter mais informações: stackoverflow.com/a/2688522/713554
Eu sugeriria executar uma VM com memória limitada e testar o software, o que seria um teste mais eficiente do que tentar preencher a memória na máquina host.
Esse método também tem a vantagem de que, se a situação de pouca memória causar erros de OOM em outro local e travar todo o sistema operacional, você apenas trava a VM que está testando na sua máquina, na qual poderá ter outros processos úteis em execução.
Além disso, se seu teste não for intensivo em CPU ou IO, você poderá executar simultaneamente instâncias dos testes em uma família de VMs com uma variedade de tamanhos de memória baixos.
Deste comentário do HN: https://news.ycombinator.com/item?id=6695581
Basta preencher / dev / shm via dd ou similar.
swapoff -a dd if=/dev/zero of=/dev/shm/fill bs=1k count=1024k
pv
estiver instalado, ajuda a ver a contagem:dd if=/dev/zero bs=1024 |pv -b -B 1024 | dd of=/dev/shm/fill bs=1024
Se você tiver ferramentas GNU básicos ( sh
, grep
, yes
e head
) você pode fazer isso:
yes | tr \\n x | head -c $BYTES | grep n
# Protip: use `head -c $((1024*1024*2))` to calculate 2MB easily
Isso funciona porque o grep carrega toda a linha de dados na RAM (eu aprendi isso de uma maneira bastante infeliz ao receber uma imagem de disco). A linha, gerado por yes
, novas linhas substituindo, será infinitamente longo, mas é limitado head
pela $BYTES
bytes, assim grep irá carregar $ bytes de memória. O próprio Grep usa como 100-200KB para mim, pode ser necessário subtraí-lo para uma quantidade mais precisa.
Se você também deseja adicionar uma restrição de tempo, isso pode ser feito facilmente bash
(não funcionará sh
):
cat <(yes | tr \\n x | head -c $BYTES) <(sleep $NumberOfSeconds) | grep n
A <(command)
coisa parece ser pouco conhecida, mas geralmente é extremamente útil, mais informações aqui: http://tldp.org/LDP/abs/html/process-sub.html
Então, o uso de cat
: cat
aguardará a conclusão das entradas até a saída e, mantendo um dos tubos abertos, manterá o grep ativo.
Se você tem pv
e deseja aumentar lentamente o uso da RAM:
yes | tr \\n x | head -c $BYTES | pv -L $BYTESPERSEC | grep n
Por exemplo:
yes | tr \\n x | head -c $((1024*1024*1024)) | pv -L $((1024*1024)) | grep n
Usará até um gigabyte a uma taxa de 1 MB por segundo. Como um bônus adicional, pv
mostrará a taxa atual de uso e o uso total até o momento. Claro que isso também pode ser feito com variantes anteriores:
yes | tr \\n x | head -c $BYTES | pv | grep n
Apenas inserir a | pv |
peça mostrará o status atual (taxa de transferência e total, por padrão, eu acho - caso contrário, veja a página do manual).
Por que outra resposta? A resposta aceita recomenda a instalação de um pacote (aposto que há uma liberação para cada chipset sem a necessidade de um gerenciador de pacotes); a resposta mais votada recomenda a compilação de um programa C (eu não tinha um compilador ou uma cadeia de ferramentas instalada para compilar para sua plataforma de destino); a segunda resposta mais votada recomenda a execução do aplicativo em uma VM (sim, deixe-me colocar o sdcard interno do telefone por USB ou algo assim e criar uma imagem de caixa virtual); o terceiro sugere modificar algo na sequência de inicialização que não preenche a RAM conforme desejado; o quarto funciona apenas na medida em que o ponto de montagem / dev / shm (1) existe e (2) é grande (a remontagem precisa de raiz); o quinto combina muitos dos itens acima sem código de exemplo; a sexta é uma ótima resposta, mas eu não a vi antes de apresentar minha própria abordagem, então pensei em adicionar o meu, também porque é mais curto lembrar ou digitar, se você não perceber que a linha memblob é realmente o cerne da questão; o sétimo novamente não responde à pergunta (usa ulimit para limitar um processo); o oitavo tenta fazer com que você instale o python; o nono acha que somos todos muito pouco criativos e, finalmente, o décimo escreveu seu próprio programa C ++, que causa o mesmo problema que a resposta mais votada.
set -e
, então eu aprendi alguma coisa :)
time yes | tr \\n x | head -c $((1024*1024*1024*10)) | grep n
(use 10 GiB de memória) leva 1 minuto e 46 segundos. A execução do programa eatmemory de julman99 em github.com/julman99/eatmemory leva 6 segundos. ... Bem, mais o tempo de download e compilação, mas compilou sem problemas ... e muito rapidamente ... na minha máquina RHEL6.4. Ainda assim, eu gosto desta solução. Por que reinventar a roda?
Eu mantenho uma função para fazer algo semelhante nos meus arquivos de ponto. https://github.com/sagotsky/.dotfiles/blob/master/.functions#L248
function malloc() {
if [[ $# -eq 0 || $1 -eq '-h' || $1 -lt 0 ]] ; then
echo -e "usage: malloc N\n\nAllocate N mb, wait, then release it."
else
N=$(free -m | grep Mem: | awk '{print int($2/10)}')
if [[ $N -gt $1 ]] ;then
N=$1
fi
sh -c "MEMBLOB=\$(dd if=/dev/urandom bs=1MB count=$N) ; sleep 1"
fi
}
Como montar uma solução python simples?
#!/usr/bin/env python
import sys
import time
if len(sys.argv) != 2:
print "usage: fillmem <number-of-megabytes>"
sys.exit()
count = int(sys.argv[1])
megabyte = (0,) * (1024 * 1024 / 8)
data = megabyte * count
while True:
time.sleep(1)
sysctl vm.swappiness=0
e definir vm.min_free_kbytes como um número pequeno, talvez 1024. Eu não tentei, mas os documentos dizem que é assim que você controla a rapidez da troca ... você deve capaz de torná-lo bastante lento, a ponto de causar uma condição OOM em sua máquina. Veja kernel.org/doc/Documentation/sysctl/vm.txt e kernel.org/doc/gorman/html/understand/understand005.html
Que tal ramfs, se existir? Montá-lo e copiar sobre um arquivo grande? Se não houver /dev/shm
e não ramfs - eu acho que um pequeno programa C que faz um malloc grande com base em algum valor de entrada? Pode ser necessário executá-lo algumas vezes ao mesmo tempo em um sistema de 32 bits com muita memória.
Se você quiser testar um processo específico com memória limitada, poderá utilizar melhor ulimit
para restringir a quantidade de memória alocável.
man setrlimit
:RLIMIT_RSS Specifies the limit (in pages) of the process's resident set (the number of virtual pages resident in RAM). This limit only has effect in Linux 2.4.x, x < 30, and there only affects calls to madvise(2) specifying MADV_WILLNEED.
Penso que este é um caso de fazer a pergunta errada e a sanidade serem abafadas por pessoas que competem pela resposta mais criativa. Se você precisar simular apenas condições de OOM, não precisará preencher memória. Basta usar um alocador personalizado e fazer com que ele falhe após um certo número de alocações. Essa abordagem parece funcionar bem o suficiente para o SQLite .
Eu escrevi este pequeno programa C ++ para isso: https://github.com/rmetzger/dynamic-ballooner
A vantagem dessa implementação é que periodicamente verifica se é necessário liberar ou realocar a memória.