Como preencher 90% da memória livre?

181

Quero fazer alguns testes com poucos recursos e para isso preciso ter 90% da memória livre cheia.

Como posso fazer isso em um *nixsistema?

Eduard Florinescu
fonte
3
Realmente tem que funcionar em qualquer sistema * nix?
um CVn
31
Em vez de preencher a memória, você poderia criar uma VM (usando janela de encaixe ou vagabundo ou algo semelhante) que tenha uma quantidade limitada de memória?
Abendigo
4
@abendigo Para um controle de qualidade, muitas das soluções apresentadas aqui são úteis: para um sistema operacional de uso geral sem uma plataforma específica, os parâmetros de inicialização da VM ou do kernel podem ser úteis, mas para um sistema incorporado onde você conhece as especificações de memória do sistema de destino, eu vá para o preenchimento da memória livre.
Eduard Florinescu
2
Caso alguém mais fique um pouco chocado com a pontuação aqui: meta.unix.stackexchange.com/questions/1513/… ?
Goldilocks

Respostas:

157

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 MemAvailablepara 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/meminfochamada com free(1)/ vm_stat(1)/ etc. se você precisar dele portátil.

tkrennwa
fonte
3
stress --vm-bytes $ (awk '/ MemFree / {printf "% d \ n", $ 2 * 0.097;}' </ proc / meminfo) k --vm-keep -m 10
Robert
1
A maior parte do MemFree é mantida pelo sistema operacional, então usei o MemAvailable. Isto deu-me o uso de 92% no OS Cent 7.stress --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 * 0.98;}' < /proc/meminfo)k --vm-keep -m 1
kujiy
É bom saber que o MemAvailable foi adicionado à "estimativa de quanta memória está disponível para iniciar novos aplicativos, sem troca", consulte git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/ … E git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/…
tkrennwa em
1
Apenas como uma observação adicional, fornecendo ambos --vm 1 and --vm-keepé muito importante. Simplesmente --vm-bytesnã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.
ffledgling 26/03
É por isso que existe -m 1. De acordo com a página de manual do estresse, -m Né a abreviação de --vm N: spawn Nworkers spinning onmalloc()/free()
tkrennwa
92

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.

Chris
fonte
25
Há muito tempo, tive que testar casos de uso semelhantes. Observei que até que você escreva algo nessa memória, ela não será realmente alocada (ou seja, até que ocorra falha na página). Não tenho certeza se mlock () cuida disso.
Poorna
2
Eu concordo com @siri; no entanto, depende de qual variante UNIX você está usando.
Anthony
2
Alguma inspiração para o código. Além disso, acho que você não precisa desbloquear / liberar a memória . O sistema operacional fará isso por você quando o processo terminar.
Sebastian
9
Você provavelmente precisa realmente gravar na memória, o kernel pode apenas se comprometer demais se você apenas o fizer mal. Se configurado para, por exemplo, o Linux permitirá que o malloc retorne com êxito sem realmente ter a memória livre e realmente aloque a memória quando estiver sendo gravada. Veja win.tue.nl/~aeb/linux/lk/lk-9.html
Bjarke Freund-Hansen em
7
@ Sebastian: callocvai 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 memsetbuffer inteiro. Veja a resposta a seguir para obter mais informações: stackoverflow.com/a/2688522/713554
Leo
45

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.

David Spillett
fonte
31

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
Damio
fonte
8
Nem todos os * nixes possuem / dev / shm. Alguma idéia mais portátil?
Tadeusz A. Kadłubowski
Se pvestiver instalado, ajuda a ver a contagem:dd if=/dev/zero bs=1024 |pv -b -B 1024 | dd of=/dev/shm/fill bs=1024
Otheus 26/09
1
Se você quer velocidade, esse método é a escolha certa! Porque ele aloca a quantidade desejada de RAM em questão de segundos. Não utilize o / dev / urandom, ele usará 100% da CPU e levará alguns minutos se sua RAM for grande. AINDA, / dev / shm tem um tamanho relativo nas distribuições modernas do Ubuntu / Debian, e possui um tamanho padrão de 50% da RAM física. Espero que você possa remontar / dev / shm ou talvez criar um novo ponto de montagem. Apenas verifique se ele tem o tamanho real que você deseja alocar.
usar o seguinte código
30
  1. execute linux;
  2. inicializar com mem=nn[KMG]o parâmetro de inicialização do kernel

(veja em linux / Documentation / kernel-parameters.txt para detalhes).

Anon
fonte
24

Se você tiver ferramentas GNU básicos ( sh, grep, yese 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 headpela $BYTESbytes, 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: cataguardará a conclusão das entradas até a saída e, mantendo um dos tubos abertos, manterá o grep ativo.

Se você tem pve 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, pvmostrará 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.

Luc
fonte
solução adorável. A única falha é que o código de saída da construção é 1 porque o grep não encontra uma correspondência. Nenhuma das soluções de stackoverflow.com/questions/6550484/… parece corrigi-lo.
Holger Brandl
@HolgerBrandl Bom ponto, eu não saberia como consertar isso. Esta é a primeira vez que ouvi de set -e, então eu aprendi alguma coisa :)
Luc
$ SECONDS não parece uma boa opção, pois é uma variável interna que reflete o tempo desde que o shell foi iniciado. consulte tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
Holger Brandl
@HolgerBrandl Boa captura, eu não sabia disso. É muito legal encontrar um terminal que esteja aberto por> 3 milhões de segundos atualmente: D. Eu atualizei a postagem.
Luc
Técnica legal! 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?
Mike S
18

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
}
valadil
fonte
1
Esta é a melhor solução IMHO, como ela basicamente precisa de dd para funcionar, todas as outras coisas podem ser contornadas em qualquer shell. Observe que ele realmente reivindica o dobro da memória que os dados que o dd produz, pelo menos temporariamente. Testado no debian 9, traço 0.5.8-2.4. Se você usar o bash para executar a parte MEMBLOB, ela ficará muito lenta e usará quatro vezes a quantidade que o dd produz.
P.Péter
16

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)
swiftcoder
fonte
7
Que irá provavelmente ser rapidamente trocados, tendo muito pouco impacto real sobre a pressão de memória (a menos que você encher-se toda a troca, assim, que vai demorar um pouco, geralmente)
Joachim Sauer
1
Por que um unix trocaria enquanto há RAM disponível? Essa é realmente uma maneira plausível de remover o cache do disco quando necessário.
Alexander Shcheblikin
@AlexanderShcheblikin Esta pergunta não é sobre a remoção do cache de disco (que é útil para testes de desempenho, mas não para testes de poucos recursos).
Gilles
1
Essa solução funcionou para consertar um Gig ou dois em meus testes, embora eu não tenha tentado estressar minha memória. Mas, @JoachimSauer, é possível definir sysctl vm.swappiness=0e 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
Mike S
simplesmente um liner para 1 GB: python -c "x = (1 * 1024 * 1024 * 1024/8) * (0,); raw_input ()"
adrianlzt
10

Que tal ramfs, se existir? Montá-lo e copiar sobre um arquivo grande? Se não houver /dev/shme 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.

nemo
fonte
8

Se você quiser testar um processo específico com memória limitada, poderá utilizar melhor ulimitpara restringir a quantidade de memória alocável.

sj26
fonte
2
Na verdade, isso não funciona no linux (não sei sobre outros * nixes). 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.
Patrick
4

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 .

Craig Barnes
fonte
3

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.

Robert Metzger
fonte