Как заполнить 90% свободной памяти?

181

Я хочу провести небольшое тестирование ресурсов, и для этого мне нужно заполнить 90% свободной памяти.

Как я могу сделать это в *nixсистеме?

Эдуард Флоринеску
источник
3
Это действительно должно работать в любой системе * nix?
CVn
31
Вместо того, чтобы просто заполнять память, не могли бы вы создать виртуальную машину (использующую Docker, или Vagrant, или что-то подобное), которая имеет ограниченный объем памяти?
Абендиго
4
@abendigo Для QA многие из представленных здесь решений полезны: для ОС общего назначения без конкретной платформы могут быть полезны параметры загрузки ВМ или ядра, но для встраиваемой системы, где вы знаете спецификацию памяти целевой системы, я бы пойти на заполнение свободной памяти.
Эдуард Флоринеску
2
В случае, если кто-то еще немного шокирован выигрышем здесь: meta.unix.stackexchange.com/questions/1513/… ?
Златовласка
Смотрите также: unix.stackexchange.com/a/1368/52956
Уилф

Ответы:

157

стресс-нг - это генератор рабочей нагрузки, который имитирует нагрузку cpu / mem / io / hdd в системах POSIX. Этот вызов должен сделать трюк в Linux <3.14:

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

Для Linux> = 3.14 вы можете MemAvailableвместо этого использовать оценку доступной памяти для новых процессов без замены:

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

Адаптируйте /proc/meminfoвызов с помощью free(1)/ vm_stat(1)/ etc. если вам нужно это портативный.

tkrennwa
источник
3
стресс --vm-байтов $ (awk '/ MemFree / {printf "% d \ n", $ 2 * 0.097;}' </ proc / meminfo) k --vm-keep -m 10
Роберт
1
Большая часть MemFree хранится в ОС, поэтому я использовал MemAvailable. Это дало мне 92% использования в Cent OS 7.stress --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 * 0.98;}' < /proc/meminfo)k --vm-keep -m 1
kujiy
Полезно знать, что MemAvailable был добавлен для «оценки того, сколько памяти доступно для запуска новых приложений без замены», см. git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/ … И git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/…
tkrennwa
1
Так же, как добавленное примечание, предоставление обоих --vm 1 and --vm-keepочень важно. Просто --vm-bytesничего не делает, и вас могут ввести в заблуждение, что вы можете выделить столько памяти, сколько вам нужно / нужно. Я получил немного, пока я не попытался проверить себя, выделив 256 ГБ памяти. Это не недостаток в ответе, он предоставляет правильные флаги, просто дополнительную осторожность.
окрыление
Вот почему есть -m 1. В соответствии со -m N--vm NNmalloc()/free()
справочной страницей
93

Вы можете записать программу на C malloc()в требуемую память, а затем использовать ее mlock()для предотвращения замены памяти.

Затем просто дайте программе подождать ввода с клавиатуры, разблокируйте память, освободите память и выйдите.

Крис
источник
25
Давным-давно мне приходилось тестировать подобный вариант использования. Я заметил, что до тех пор, пока вы не напишите что-то в эту память, оно не будет фактически выделено (т.е. пока не произойдет сбой страницы). Я не уверен, что mlock () позаботится об этом.
Пурна
2
Я согласен с @siri; однако это зависит от того, какой вариант UNIX вы используете.
Энтони
2
Некоторое вдохновение для кода. Кроме того, я думаю, что вам не нужно разблокировать / освободить память . ОС сделает это за вас, когда ваш процесс закончится.
Себастьян
9
Вы, вероятно, должны на самом деле записывать в память, ядро ​​может просто перегружаться, если вы только неправильно его размещаете. Если он настроен на, например, Linux позволит malloc успешно возвращаться без фактического освобождения памяти, и только фактически выделяет память, когда она записывается. См. Win.tue.nl/~aeb/linux/lk/lk-9.html
Бьярке Фрейнд-Хансен,
7
@Sebastian: callocстолкнется с той же проблемой IIRC. Вся память будет просто указывать на одну и ту же страницу, доступную только для чтения. На самом деле он не будет выделен, пока вы не попытаетесь записать в него (что не будет работать, поскольку доступно только для чтения). Единственный способ быть действительно уверенным в том, что я знаю, это memsetиспользовать весь буфер. Для получения дополнительной информации см. Следующий ответ stackoverflow.com/a/2688522/713554
Лев
45

Я бы предложил запустить виртуальную машину с ограниченной памятью и протестировать программное обеспечение, которое было бы более эффективным, чем попытка заполнить память на хост-машине.

Этот метод также имеет то преимущество, что если ситуация с нехваткой памяти вызывает ошибки OOM в другом месте и приводит к зависанию всей ОС, вы вешаете только проверяемую виртуальную машину, а не свою машину, на которой могут выполняться другие полезные процессы.

Кроме того, если ваше тестирование не требует значительных ресурсов процессора или ввода-вывода, вы можете одновременно запускать экземпляры тестов на семействе виртуальных машин с различными объемами памяти.

Дэвид Спиллетт
источник
31

Из этого комментария HN: https://news.ycombinator.com/item?id=6695581

Просто заполните / dev / shm через dd или аналогичный.

swapoff -a
dd if=/dev/zero of=/dev/shm/fill bs=1k count=1024k
damio
источник
8
Не все * nixes имеют / dev / shm. Есть еще портативная идея?
Тадеуш А. Кадлубовский
Если pvустановлено, это помогает увидеть счет:dd if=/dev/zero bs=1024 |pv -b -B 1024 | dd of=/dev/shm/fill bs=1024
Otheus
1
Если вы хотите скорость, этот метод является правильным выбором! Потому что он выделяет желаемый объем оперативной памяти в считанные секунды. Не включайте / dev / urandom, он будет использовать 100% ЦП и займет несколько минут, если у вас большой объем ОЗУ. ДА, / dev / shm имеет относительный размер в современных дистрибутивах Ubuntu / Debian, по умолчанию он равен 50% физической памяти. Надеюсь, вы можете перемонтировать / dev / shm или, возможно, создать новую точку монтирования. Просто убедитесь, что он имеет фактический размер, который вы хотите выделить.
develCuy
30
  1. запустить Linux;
  2. загрузка с mem=nn[KMG]параметром загрузки ядра

(подробности смотрите в linux / Documentation / kernel-parameters.txt).

скоро
источник
24

Если у вас есть основные инструменты GNU ( sh, grep, yesи head) , вы можете сделать это:

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

Это работает, потому что grep загружает всю строку данных в ОЗУ (я узнал об этом довольно неудачным образом, когда копировал образ диска). Линии, генерируется yes, замещающие символами новой строки, будут бесконечно долго, но ограничены headв $BYTESбайты, таким образом , Grep будет загружать $ Байт в памяти. Сам Grep использует как 100-200KB для меня, возможно, вам придется вычесть это для более точной суммы.

Если вы также хотите добавить ограничение по времени, это можно сделать довольно легко в bash(не будет работать sh):

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

Эта <(command)вещь, кажется, малоизвестна, но часто чрезвычайно полезна, больше информации об этом здесь: http://tldp.org/LDP/abs/html/process-sub.html

Затем для использования cat: catбудет ждать завершения ввода до выхода, а если оставить один из каналов открытым, он сохранит работу grep.

Если у вас есть pvи вы хотите медленно увеличивать использование оперативной памяти:

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

Например:

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

Будет использовать до гигабайта со скоростью 1 МБ в секунду. В качестве дополнительного бонуса, pvпокажет вам текущий уровень использования и общее использование на данный момент. Конечно, это также может быть сделано с предыдущими вариантами:

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

Просто вставка | pv |части покажет вам текущее состояние (пропускная способность и общее количество, по умолчанию, я думаю - в противном случае смотрите страницу man (ual)).


Почему другой ответ? В принятом ответе рекомендуется установить пакет (держу пари, что для каждого набора микросхем есть релиз, не требующий менеджера пакетов); В ответе, получившем наибольшее количество голосов, рекомендуется компилировать программу на Си (у меня не было компилятора или набора инструментов для компиляции для вашей целевой платформы); во втором ответе с наибольшим количеством голосов рекомендуется запустить приложение на виртуальной машине (да, я просто добавлю внутреннюю SD-карту этого телефона через USB или что-то еще и создаю образ виртуальной коробки); третий предлагает модифицировать что-то в последовательности загрузки, которая не заполняет RAM должным образом; четвертый работает только в том случае, если точка монтирования / dev / shm (1) существует и (2) велика (для перемонтирования требуется root); пятый сочетает в себе многие из вышеперечисленных без примера кода; шестой - отличный ответ, но я не видел его до того, как придумал свой собственный подход, поэтому я решил добавить свою собственную, в том числе и потому, что ее короче запомнить или напечатать, если вы не видите, что линия мембраны - это суть дела; седьмой снова не отвечает на вопрос (вместо него используется ulimit для ограничения процесса); восьмой пытается заставить вас установить python; Девятый думает, что мы все очень не творческие, и, наконец, десятый написал свою собственную программу на C ++, которая вызывает ту же проблему, что и ответ с наибольшим количеством голосов.

Люк
источник
прекрасное решение. Единственным недостатком является то, что код выхода конструкции равен 1, потому что grep не находит соответствия. Ни одно из решений от stackoverflow.com/questions/6550484/… кажется, это не исправить.
Хольгер Брандл
@HolgerBrandl Хорошо, я не знаю, как это исправить. Это первый раз, когда я услышал set -e, поэтому я только что-то узнал :)
Люк,
$ SECONDS не кажется хорошим выбором, поскольку это встроенная переменная, отражающая время с момента запуска оболочки. см. tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
Хольгер Брандл
@HolgerBrandl Хорошо, я этого не знал. В общем, круто найти терминал, который открыт в течение> 3 миллионов секунд: D. Я обновил пост.
Люк
Классная техника! time yes | tr \\n x | head -c $((1024*1024*1024*10)) | grep n(использовать память 10 ГиБ) занимает 1 минуту 46 секунд. Запуск программы еды на julman99 по адресу github.com/julman99/eatmemory занимает 6 секунд. ... Ну, плюс время загрузки и компиляции, но оно скомпилировано без проблем ... и очень быстро ... на моей машине RHEL6.4. Тем не менее, мне нравится это решение. Зачем изобретать велосипед?
Майк С
18

У меня есть функция для создания чего-то похожего в моих точечных файлах. 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
источник
1
ИМХО, это самое хорошее решение, так как для работы ему нужен только dd, все остальные вещи можно обойти в любой оболочке. Обратите внимание, что на самом деле он требует вдвое больше памяти, чем производит dd, по крайней мере, временно. Протестировано на Debian 9, тире 0.5.8-2.4. Если вы используете bash для запуска части MEMBLOB, она становится действительно медленной и использует в четыре раза больше, чем производит dd.
Петр
16

Как найти простое решение на 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
источник
7
Это, вероятно, будет быстро заменено, что окажет очень незначительное влияние на нагрузку на память (если вы не заполняете также весь обмен, который обычно занимает некоторое время)
Joachim Sauer
1
Зачем юниксу менять местами при наличии свободной оперативной памяти? На самом деле это правдоподобный способ высвободить дисковый кеш при необходимости.
Александр Щебликин
@AlexanderShcheblikin Этот вопрос не касается удаления дискового кэша (который полезен для тестирования производительности, но не для тестирования с ограниченными ресурсами).
Жиль
1
Это решение сработало для того, чтобы собрать в одном тесте один или два гигабайта, хотя я не пытался подчеркнуть свою память. Но, @JoachimSauer, можно установить sysctl vm.swappiness=0и, кроме того, установить vm.min_free_kbytes на небольшое число, возможно, 1024. Я не пробовал, но в документах говорится, что именно так вы контролируете скорость замены ... вы должны в состоянии сделать это довольно медленно, вплоть до возникновения состояния OOM на вашей машине. См. Kernel.org/doc/Documentation/sysctl/vm.txt и kernel.org/doc/gorman/html/understand/understand005.html
Майк С,
просто один вкладыш на 1 ГБ: python -c "x = (1 * 1024 * 1024 * 1024/8) * (0,); raw_input ()"
adrianlzt
10

Как насчет ramfs, если он существует? Смонтировать и скопировать большой файл? Если нет /dev/shmи нет ramfs - я думаю, крошечная C-программа, которая делает большой malloc на основе некоторого входного значения? Возможно, придется запускать его несколько раз одновременно на 32-битной системе с большим объемом памяти.

Немо
источник
8

Если вы хотите протестировать определенный процесс с ограниченной памятью, вам лучше использовать ulimitограниченный объем выделяемой памяти.

sj26
источник
2
На самом деле это не работает в Linux (не знаю о других * 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.
Патрик
4

Я думаю, что это тот случай, когда задают неправильный вопрос, и люди, борющиеся за самый креативный ответ, заглушают здравомыслие. Если вам нужно только имитировать условия ООМ, вам не нужно заполнять память. Просто используйте пользовательский распределитель, и он завершится ошибкой после определенного количества распределений. Этот подход, кажется, работает достаточно хорошо для SQLite .

Крейг Барнс
источник
3

Я написал эту маленькую C ++ программу для этого: https://github.com/rmetzger/dynamic-ballooner

Преимущество этой реализации заключается в том, что она периодически проверяет, нужно ли освободить или перераспределить память.

Роберт Метцгер
источник