Jak wypełnić 90% wolnej pamięci?

181

Chcę przeprowadzić testowanie przy niskim zużyciu zasobów i do tego muszę mieć 90% wolnej pamięci.

Jak mogę to zrobić w *nixsystemie?

Eduard Florinescu
źródło
3
Czy to naprawdę musi działać na dowolnym systemie * nix?
CVn
31
Zamiast jutra wypełniającego pamięć, czy mógłbyś zamiast tego stworzyć maszynę wirtualną (używając dokera, włóczęgi lub czegoś podobnego), która ma ograniczoną ilość pamięci?
abendigo,
4
@abendigo W przypadku kontroli jakości przydatne jest wiele rozwiązań przedstawionych tutaj: w systemie operacyjnym ogólnego zastosowania bez konkretnej platformy parametry rozruchowe maszyny wirtualnej lub jądra mogą być przydatne, ale dla systemu wbudowanego, w którym znasz specyfikację pamięci systemu docelowego, chciałbym idź do wypełnienia wolnej pamięci.
Eduard Florinescu
2
Jeśli ktoś inny jest trochę zszokowany wynikiem tutaj: meta.unix.stackexchange.com/questions/1513/... ?
goldilocks

Odpowiedzi:

156

stress-ng to generator obciążenia, który symuluje obciążenie procesora / mem / io / hdd w systemach POSIX. To wywołanie powinno załatwić sprawę w Linuksie <3.14:

stress-ng --vm-bytes $(awk '/MemFree/{printf "%d\n", $2 * 0.9;}' < /proc/meminfo)k --vm-keep -m 1

W przypadku systemu Linux> = 3.14 MemAvailablezamiast tego można użyć do oszacowania dostępnej pamięci dla nowych procesów bez zamiany:

stress-ng --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 * 0.9;}' < /proc/meminfo)k --vm-keep -m 1

Dostosuj /proc/meminfopołączenie za pomocą free(1)/ vm_stat(1)/ etc. jeśli potrzebujesz go przenośnego.

tkrennwa
źródło
3
stres --vm-bytes $ (awk '/ MemFree / {printf "% d \ n", 2 * 0,097;}' </ proc / meminfo) k --vm-keep -m 10
Robert
1
Większość MemFree jest przechowywana przez system operacyjny, więc zamiast tego użyłem MemAvailable. Dało mi to 92% użycia w Cent OS 7.stress --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 * 0.98;}' < /proc/meminfo)k --vm-keep -m 1
kujiy
dobrze wiedzieć, MemAvailable została dodana do „oszacowania ilości dostępnej pamięci do uruchamiania nowych aplikacji, bez zamiany”, patrz git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/ … I git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/…
tkrennwa
1
Jako dodatkową notatkę, pod warunkiem, że oba --vm 1 and --vm-keepsą bardzo ważne. Po prostu --vm-bytesnic nie robi i możesz zostać wprowadzony w błąd, że możesz przydzielić tyle pamięci, ile potrzebujesz / chcesz. Uderzyło mnie to, dopóki nie spróbowałem sprawdzić zdrowia psychicznego, przydzielając 256G pamięci. To nie jest wada w odpowiedzi, zapewnia prawidłowe flagi, a jedynie dodatkową ostrożność.
sfledgling
Oto dlaczego -m 1. Według strony stresu, -m Njest skrót od --vm N: spawn Npracowników spinning onmalloc()/free()
tkrennwa
92

Możesz napisać program C do malloc()wymaganej pamięci, a następnie użyć, mlock()aby zapobiec zamianie pamięci.

Następnie pozwól programowi czekać na wprowadzenie danych z klawiatury i odblokuj pamięć, zwolnij pamięć i wyjdź.

Chris
źródło
25
Dawno temu musiałem przetestować podobny przypadek użycia. Zauważyłem, że dopóki nie napiszesz czegoś do tej pamięci, nie zostanie ona faktycznie przydzielona (tj. Dopóki nie nastąpi błąd strony). Nie jestem pewien, czy mlock () się tym przejmuje.
Poorna,
2
Zgadzam się z @siri; zależy to jednak od używanego wariantu UNIX.
Anthony
2
Trochę inspiracji do kodu. Co więcej, myślę , że nie musisz odblokowywać / zwalniać pamięci . System operacyjny zrobi to za Ciebie po zakończeniu procesu.
Sebastian,
9
Prawdopodobnie będziesz musiał napisać do pamięci, jądro może po prostu przesadzić, jeśli tylko to zrobisz. Jeśli jest skonfigurowany, np. Linux pozwoli Mallocowi powrócić bez faktycznego zwolnienia pamięci i faktycznie przydzieli pamięć tylko wtedy, gdy jest zapisywana. Zobacz win.tue.nl/~aeb/linux/lk/lk-9.html
Bjarke Freund-Hansen
7
@Sebastian: napotka callocten sam problem IIRC. Cała pamięć będzie po prostu wskazywać tę samą stronę zerowaną tylko do odczytu. W rzeczywistości nie zostanie przydzielony, dopóki nie spróbujesz do niego napisać (co nie będzie działać, ponieważ jest tylko do odczytu). Jedynym sposobem, aby być naprawdę pewnym, że wiem, jest zrobienie memsetcałego bufora. Aby uzyskać więcej informacji, zobacz następującą odpowiedź stackoverflow.com/a/2688522/713554
Leo
45

Sugerowałbym uruchomienie maszyny wirtualnej z ograniczoną pamięcią i przetestowanie oprogramowania, co byłoby bardziej wydajnym testem niż próba zapełnienia pamięci na komputerze hosta.

Ta metoda ma również tę zaletę, że jeśli sytuacja braku pamięci powoduje błędy OOM w innym miejscu i zawiesza cały system operacyjny, zawieszasz tylko testowaną maszynę wirtualną, a nie maszynę, na której mogą działać inne przydatne procesy.

Ponadto, jeśli testowanie nie wymaga użycia procesora ani operacji we / wy, można jednocześnie uruchamiać instancje testów na rodzinie maszyn wirtualnych o różnych małych rozmiarach pamięci.

David Spillett
źródło
31

Z tego komentarza HN: https://news.ycombinator.com/item?id=6695581

Wystarczy wypełnić / dev / shm przez dd lub podobny.

swapoff -a
dd if=/dev/zero of=/dev/shm/fill bs=1k count=1024k
Damio
źródło
8
Nie wszystkie * nixy mają / dev / shm. Jakiś bardziej przenośny pomysł?
Tadeusz A. Kadłubowski
Jeśli pvjest zainstalowany, pomaga zobaczyć liczbę:dd if=/dev/zero bs=1024 |pv -b -B 1024 | dd of=/dev/shm/fill bs=1024
Otheus
1
Jeśli chcesz prędkości, ta metoda jest właściwym wyborem! Ponieważ przydziela żądaną ilość pamięci RAM w ciągu kilku sekund. Nie przechodź na / dev / urandom, zużyje 100% procesora i zajmie kilka minut, jeśli pamięć RAM jest duża. JESZCZE, / dev / shm ma względny rozmiar we współczesnych dystrybucjach Ubuntu / Debian, ma rozmiar domyślnie równy 50% fizycznej pamięci RAM. Mam nadzieję, że możesz zamontować ponownie / dev / shm lub utworzyć nowy punkt montowania. Upewnij się tylko, że ma rzeczywisty rozmiar, który chcesz przydzielić.
develCuy,
30
  1. uruchomić Linux;
  2. boot z mem=nn[KMG]parametrem bootowania jądra

(szczegóły w linux / Documentation / kernel-parameters.txt).

Zaraz
źródło
24

Jeśli masz podstawowe narzędzia GNU ( sh, grep, yesi head) można to zrobić:

yes | tr \\n x | head -c $BYTES | grep n
# Protip: use `head -c $((1024*1024*2))` to calculate 2MB easily

Działa to, ponieważ grep ładuje całą linię danych do pamięci RAM (nauczyłem się tego w dość niefortunny sposób podczas grepowania obrazu dysku). Linia, generowane przez yeszastąpienie nowymi liniami, będzie nieskończenie długo, ale jest ograniczona headdo $BYTESbajtów, co grep załaduje $ bajtów pamięci. Sam Grep używa dla mnie 100-200 KB, być może będziesz musiał go odjąć, aby uzyskać dokładniejszą kwotę.

Jeśli chcesz również dodać ograniczenie czasowe, możesz to zrobić dość łatwo w bash(nie będzie działać sh):

cat <(yes | tr \\n x | head -c $BYTES) <(sleep $NumberOfSeconds) | grep n

Sprawa <(command)wydaje się mało znana, ale często bardzo przydatna, więcej informacji na ten temat można znaleźć tutaj: http://tldp.org/LDP/abs/html/process-sub.html

Następnie użycie cat: catzaczeka na zakończenie wprowadzania danych aż do wyjścia, a utrzymywanie jednej z rur otwartych utrzyma grep przy życiu.

Jeśli masz pvi chcesz powoli zwiększać ilość pamięci RAM, użyj:

yes | tr \\n x | head -c $BYTES | pv -L $BYTESPERSEC | grep n

Na przykład:

yes | tr \\n x | head -c $((1024*1024*1024)) | pv -L $((1024*1024)) | grep n

Zużywa do gigabajta z prędkością 1 MB na sekundę. Jako dodatkowy bonus pvpokaże ci aktualny poziom użytkowania i całkowite wykorzystanie do tej pory. Oczywiście można to również zrobić w przypadku poprzednich wariantów:

yes | tr \\n x | head -c $BYTES | pv | grep n

Po prostu wstawienie | pv |części pokaże ci aktualny status (domyślnie przepustowość i całkowity, domyślnie - inaczej zobacz stronę man (ual)).


Dlaczego kolejna odpowiedź? Zaakceptowana odpowiedź zaleca zainstalowanie pakietu (założę się, że dla każdego mikroukładu dostępna jest wersja bez menedżera pakietów); najczęściej głosowana odpowiedź zaleca kompilację programu w języku C (nie miałem zainstalowanego kompilatora ani zestawu narzędzi do kompilacji dla platformy docelowej); druga najczęściej głosowana odpowiedź zaleca uruchomienie aplikacji na maszynie wirtualnej (tak, pozwól mi po prostu dodać wewnętrzną kartę SD tego telefonu nad USB lub coś takiego i stworzyć obraz Virtualbox); trzeci sugeruje modyfikację czegoś w sekwencji rozruchowej, która nie wypełnia pamięci RAM zgodnie z potrzebami; czwarty działa tylko w takim stopniu, w jakim istnieje punkt montowania / dev / shm (1), a (2) jest duży (ponowne podłączanie wymaga roota); piąty łączy wiele powyższych bez przykładowego kodu; szósta to świetna odpowiedź, ale nie widziałem tej odpowiedzi, zanim wpadłem na własne podejście, więc pomyślałem, że dodam własne, także dlatego, że krótsze jest zapamiętywanie lub pisanie, jeśli nie widzisz, że linia memblob jest sednem sprawy; siódmy ponownie nie odpowiada na pytanie (zamiast tego używa ulimit, aby ograniczyć proces); ósma próbuje zmusić cię do zainstalowania Pythona; dziewiąta uważa, że ​​wszyscy jesteśmy bardzo mało kreatywni, a wreszcie dziesiąta napisała swój własny program C ++, który powoduje ten sam problem, co najczęściej głosowana odpowiedź.

Luc
źródło
cudowne rozwiązanie. Jedynym błędem jest to, że kod wyjścia konstrukcji wynosi 1, ponieważ grep nie znajduje dopasowania. Żadne z rozwiązań z stackoverflow.com/questions/6550484/... nie wydaje się tego naprawić.
Holger Brandl
@HolgerBrandl Dobra uwaga, nie wiedziałbym, jak to naprawić. Po raz pierwszy o tym słyszałem set -e, więc właśnie się czegoś nauczyłem :)
Luc
$ SECONDS nie wydaje się dobrym wyborem, ponieważ jest wbudowaną zmienną odzwierciedlającą czas od uruchomienia powłoki. patrz tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
Holger Brandl
@HolgerBrandl Dobry połów, nie wiedziałem o tym. Miło jest znaleźć terminal, który jest otwarty przez> 3 miliony sekund: D. Zaktualizowałem post.
Luc
Fajna technika! time yes | tr \\n x | head -c $((1024*1024*1024*10)) | grep n(użyj pamięci 10 GiB) zajmuje 1 minutę 46 sekund. Uruchomienie programu eatmemory julman99 na github.com/julman99/eatmemory zajmuje 6 sekund. ... Cóż, plus czas pobierania i kompilacji, ale skompilowałem bez problemu ... i bardzo szybko ... na moim komputerze RHEL6.4. Mimo to podoba mi się to rozwiązanie. Po co wymyślać koło ponownie?
Mike S
18

Utrzymuję funkcję robienia czegoś podobnego w moich plikach dot. 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
}
waladil
źródło
1
Jest to najładniejsze rozwiązanie IMHO, ponieważ w zasadzie wymaga tylko dd do działania, wszystkie inne rzeczy można obejść w dowolnej powłoce. Zauważ, że faktycznie zajmuje dwa razy więcej pamięci niż dane dd, przynajmniej tymczasowo. Testowany na Debianie 9, myślnik 0.5.8-2.4. Jeśli użyjesz bash do uruchomienia części MEMBLOB, staje się on naprawdę wolny i używa czterokrotnie większej ilości niż dd.
P.Péter
16

Jak obliczyć proste rozwiązanie python?

#!/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
źródło
7
To prawdopodobnie szybko zostanie zamienione, wywierając bardzo niewielki faktyczny wpływ na presję pamięci (chyba że wypełnisz również całą wymianę, co zwykle potrwa chwilę)
Joachim Sauer
1
Dlaczego unix miałby zamieniać się, gdy dostępna jest pamięć RAM? Jest to w rzeczywistości możliwy sposób na eksmisję pamięci podręcznej dysku, gdy zajdzie taka potrzeba.
Alexander Shcheblikin
@AlexanderShcheblikin To pytanie nie dotyczy eksmisji pamięci podręcznej dysku (co jest przydatne do testowania wydajności, ale nie do testowania niskich zasobów).
Gilles
1
To rozwiązanie sprawiło, że w moich testach udało się ułożyć Gig lub dwa, choć nie próbowałem obciążać pamięci. Ale, @JoachimSauer, można ustawić, sysctl vm.swappiness=0a ponadto ustawić vm.min_free_kbytes na małą liczbę, może 1024. Nie próbowałem tego, ale doktorzy mówią, że w ten sposób kontrolujesz szybkość zamiany ... powinieneś być jest w stanie spowolnić go do tego stopnia, że ​​powoduje stan OOM na twoim komputerze. Zobacz kernel.org/doc/Documentation/sysctl/vm.txt i kernel.org/doc/gorman/html/understand/understand005.html
Mike S
po prostu jedna linijka na 1 GB: python -c "x = (1 * 1024 * 1024 *
1024/8
10

Co powiesz na ramfs, jeśli istnieje? Zamontować i skopiować duży plik? Jeśli nie /dev/shmma ramfów i nie ma - myślę, że mały program C robi duży malloc w oparciu o jakąś wartość wejściową? Może trzeba go uruchomić kilka razy na raz na 32-bitowym systemie z dużą ilością pamięci.

nemo
źródło
8

Jeśli chcesz przetestować konkretny proces z ograniczoną pamięcią, lepiej użyć ulimitograniczania ilości przydzielanej pamięci.

sj26
źródło
2
W rzeczywistości nie działa to na Linuksie (nie wiem o innych * nixach). 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

Myślę, że jest to przypadek zadawania niewłaściwego pytania i zdrowego rozsądku zagłuszanego przez ludzi rywalizujących o najbardziej kreatywną odpowiedź. Jeśli potrzebujesz tylko zasymulować warunki OOM, nie musisz wypełniać pamięci. Wystarczy użyć niestandardowego programu przydzielającego i spowodować jego awarię po określonej liczbie alokacji. To podejście wydaje się działać wystarczająco dobrze dla SQLite .

Craig Barnes
źródło
3

Napisałem do tego mały program C ++: https://github.com/rmetzger/dynamic-ballooner

Zaletą tej implementacji jest to, że okresowo sprawdza, czy trzeba zwolnić lub ponownie przydzielić pamięć.

Robert Metzger
źródło