У oom-killer обычно плохая репутация среди пользователей Linux. Возможно, это одна из причин, по которой Linux вызывает его только тогда, когда у него нет другого выбора. Он заменит среду рабочего стола, удалит весь кэш страниц и очистит каждый буфер, прежде чем в конечном итоге убьет процесс. По крайней мере, я так думаю. Мне еще предстоит набраться терпения, чтобы дождаться этого, сидя перед неотвечающей системой.
Это заставило меня и других людей задуматься, можно ли настроить oom-killer для более раннего вмешательства: reddit r/linux, superuser.com, unix.stackexchange.com.
Как оказалось, нет, не может. По крайней мере, используя встроенный в ядро oom-killer. Однако в пользовательском пространстве мы можем делать все, что захотим.
Earlyoom хочет быть простым и надежным. Он написан на чистом C без каких-либо зависимостей. Обширный набор тестов (юнит- и интеграционные тесты) написан на Go.
Earlyoom проверяет объем доступной памяти и свободный своп до 10 раз в секунду (реже, если свободной памяти много). По умолчанию, если оба значения ниже 10%, будет уничтожен самый крупный процесс (самый высокий oom_score
). Процентное значение настраивается с помощью аргументов командной строки.
В выводе free -m
ниже доступная память составляет 2170 МБ, а свободный своп — 231 МБ.
total used free shared buff/cache available
Mem: 7842 4523 137 841 3182 2170
Swap: 1023 792 231
Почему проверяется «доступная» память, а не «свободная» память? В работоспособной системе Linux «свободная» память должна быть близка к нулю, поскольку Linux использует всю доступную физическую память для кэширования доступа к диску. Эти кэши можно удалить в любой момент, когда память понадобится для чего-то другого.
За это отвечает «доступная» память. Он суммирует всю память, которая не используется или может быть немедленно освобождена.
Обратите внимание, что вам нужна последняя free
версия и ядро Linux 3.14+, чтобы увидеть столбец «доступно». Если у вас недавнее ядро, но старая версия free
, вы можете получить значение из grep MemAvailable /proc/meminfo
.
Когда объем доступной памяти и свободной подкачки упадет ниже 10 % от общей памяти, доступной процессам пользовательского пространства (=total-shared), он отправит сигнал SIGTERM
процессу, который использует больше всего памяти, по мнению ядра ( /proc/*/oom_score
).
Earlyoom не использует echo f > /proc/sysrq-trigger
потому что:
В некоторых версиях ядра (проверено на v4.0.5) запуск ядра oom killer вручную вообще не работает. То есть он может освободить только некоторую часть графической памяти (которая будет немедленно снова выделена) и фактически не завершить какой-либо процесс. Здесь вы можете увидеть, как это выглядит на моей машине (встроенная графика Intel).
Эта проблема исправлена в Linux v5.17 (коммит f530243a).
Как и ядро Linux, Earlyoom находит свою жертву, читая /proc/*/oom_score
.
Около 2 MiB
( VmRSS
), хотя только 220 kiB
— частная память ( RssAnon
). Остальное — это библиотека libc ( RssFile
), которая используется совместно с другими процессами. Вся память блокируется с помощью mlockall()
чтобы Earlyoom не замедлялся в ситуациях с нехваткой памяти.
Собрать самостоятельно легко:
git clone https://github.com/rfjakob/earlyoom.git
cd earlyoom
make
Необязательно: Запустите встроенные самотестирования:
make test
Запустите Earlyoom автоматически, зарегистрировав его как службу:
sudo make install # systemd
sudo make install-initscript # non-systemd
Обратите внимание, что для систем с отключенным SELinux (Ubuntu 19.04, Debian 9...) предупреждения chcon, сообщающие о невозможности установки контекста, можно безопасно игнорировать.
Для Debian 10+ и Ubuntu 18.04+ есть пакет Debian:
sudo apt install earlyoom
Для Fedora и RHEL 8 с EPEL существует пакет Fedora:
sudo dnf install earlyoom
sudo systemctl enable --now earlyoom
Для Arch Linux есть пакет Arch Linux:
sudo pacman -S earlyoom
sudo systemctl enable --now earlyoom
Доступность в других дистрибутивах: см. страницу релогии.
Просто запустите только что скомпилированный исполняемый файл:
./earlyoom
Он сообщит вам, сколько у вас памяти и подкачки, каков минимум, сколько памяти доступно и сколько подкачки свободно.
./earlyoom
eearlyoom v1.8
mem total: 23890 MiB, user mem total: 21701 MiB, swap total: 8191 MiB
sending SIGTERM when mem avail <= 10.00% and swap free <= 10.00%,
SIGKILL when mem avail <= 5.00% and swap free <= 5.00%
mem avail: 20012 of 21701 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%)
mem avail: 20031 of 21721 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%)
mem avail: 20033 of 21723 MiB (92.22%), swap free: 5251 of 8191 MiB (64.11%)
[...]
Если значения падают ниже минимума, процессы завершаются до тех пор, пока оно снова не превысит минимум. Каждое действие записывается в stderr. Если вы используете Earlyoom как службу systemd, вы можете просмотреть последние 10 строк, используя
systemctl status earlyoom
Чтобы увидеть earlyoom
в действии, создайте/моделируйте утечку памяти и позвольте earlyoom
делать то, что он делает:
tail /dev/zero
Если вам нужны какие-либо дальнейшие действия после завершения процесса earlyoom
(например, отправка электронных писем), вы можете проанализировать журналы следующим образом:
sudo journalctl -u earlyoom | grep sending
Пример вывода приведенной выше тестовой команды ( tail /dev/zero
) будет выглядеть так:
Feb 20 10:59:34 debian earlyoom[10231]: sending SIGTERM to process 7378 uid 1000 "tail": oom_score 156, VmRSS 4962 MiB
Для более старых версий
earlyoom
используйте:sudo journalctl -u earlyoom | grep -iE "(sending|killing)"
Начиная с версии 1.6, Earlyoom может отправлять уведомления об остановленных процессах через системную d-шину. Передайте -n
чтобы включить их.
Чтобы действительно видеть уведомления в сеансе графического интерфейса, вам необходимо запустить systembus-notify от имени вашего пользователя.
Кроме того, Earlyoom может выполнять сценарий для каждого убитого процесса, предоставляя информацию о процессе через переменные среды EARLYOOM_PID
, EARLYOOM_UID
и EARLYOOM_NAME
. Передайте -N /path/to/script
чтобы включить.
Предупреждение: в режиме сухого запуска сценарий будет выполняться в быстрой последовательности, убедитесь, что у вас установлено какое-то ограничение скорости.
Флаг командной строки --prefer
указывает процессы, которые предпочитают уничтожать; аналогично, --avoid
указывает процессы, которые следует избегать. Подробности см. на https://github.com/rfjakob/earlyoom/blob/master/MANPAGE.md#--prefer-regex.
Если вы используете Earlyoom как системную службу (через systemd или init.d), вы можете настроить его конфигурацию с помощью файла, предоставленного в /etc/default/earlyoom
. В комментариях файл уже содержит несколько примеров, которые вы можете использовать для создания собственного набора конфигурации на основе поддерживаемых параметров командной строки, например:
EARLYOOM_ARGS="-m 5 -r 60 --avoid '(^|/)(init|Xorg|ssh)$' --prefer '(^|/)(java|chromium)$'"
После настройки файла просто перезапустите службу, чтобы изменения вступили в силу. Например, для systemd:
systemctl restart earlyoom
Обратите внимание, что этот файл конфигурации не влияет на экземпляры Earlyoom за пределами systemd/init.d.
earlyoom v1.8
Usage: ./earlyoom [OPTION]...
-m PERCENT[,KILL_PERCENT] set available memory minimum to PERCENT of total
(default 10 %).
earlyoom sends SIGTERM once below PERCENT, then
SIGKILL once below KILL_PERCENT (default PERCENT/2).
-s PERCENT[,KILL_PERCENT] set free swap minimum to PERCENT of total (default
10 %).
Note: both memory and swap must be below minimum for
earlyoom to act.
-M SIZE[,KILL_SIZE] set available memory minimum to SIZE KiB
-S SIZE[,KILL_SIZE] set free swap minimum to SIZE KiB
-n enable d-bus notifications
-N /PATH/TO/SCRIPT call script after oom kill
-g kill all processes within a process group
-d, --debug enable debugging messages
-v print version information and exit
-r INTERVAL memory report interval in seconds (default 1), set
to 0 to disable completely
-p set niceness of earlyoom to -20 and oom_score_adj to
-100
--ignore-root-user do not kill processes owned by root
--sort-by-rss find process with the largest rss (default oom_score)
--prefer REGEX prefer to kill processes matching REGEX
--avoid REGEX avoid killing processes matching REGEX
--ignore REGEX ignore processes matching REGEX
--dryrun dry run (do not kill any processes)
--syslog use syslog instead of std streams
-h, --help this help text
Подробности смотрите на странице руководства.
Отчеты об ошибках и запросы на включение приветствуются через github. В частности, я рад принять
v1.8.2, 7 мая 2024 г.
earlyoom.service
process_mrelease
в разрешенные системные вызовы (фиксация)IPAddressDeny
(фиксация)-p
(фиксировать)v1.8.1, 17 апреля 2024 г.
v1.8, 15 апреля 2024 г.
user mem total
/ meminfo_t.UserMemTotal
и рассчитайте MemAvailablePercent на его основе (фиксация, дополнительная информация на странице руководства)process_mrelease
(#266)NO_COLOR
(https://no-color.org/)--sort-by-rss
, спасибо @RanHuang! Это выберет процесс для уничтожения акк. к самому большому RSS вместо самого большого oom_score.v1.7, 5 марта 2022 г.
-N
для запуска сценария каждый раз при завершении процесса (фиксация, раздел man-страницы)-g
, чтобы уничтожить всю группу процессов (#247).-i
(игнорируется для совместимости), он не работает должным образом в ядрах Linux 5.9+ (#234).v1.6.2, 14 октября 2020 г.
1.6.1, 07.07.2020
1.6, 11.04.2020
notify-send
на dbus-send
/systembus-notify (#183).-n
/ -N
теперь включает новую логику/proc
, смонтированный с помощью Hidepid (проблема № 184).v1.5, 22 марта 2020 г.
-p
: установить oom_score_adj на -100
вместо -1000
(#170)-M
и -m
, так и -S
и -s
. Будет использовано меньшее значение (преобразованное в проценты).earlyoom.default
на 1 час вместо 1 минуты (#177).v1.4, 1 марта 2020 г.
uid
завершенных процессов в дополнение к pid и имени.make test
)cppcheck
если он доступен.make bench
)earlyoom.service
v1.3.1, 27 февраля 2020 г.
v1.3, 26 мая 2019 г.
v1.2, 28 октября 2018 г.
-k
, теперь игнорируется для совместимости) (проблема № 80).v1.1, 7 июля 2018 г.
--help
в дополнение к -h
-S
(фиксация)v1.0, 28 января 2018 г.
--prefer
и --avoid
(@TomJohnZ)-n
и -N
v0.12: Добавлены опции -M
и -S
(@nailgun); добавить справочную страницу, параметризовать Makefile (@yangfl)
v0.11: Исправлено неопределенное поведение в get_entry_fatal (отсутствует возврат, фиксация)
v0.10: разрешено переопределять переменную VERSION в Makefile, чтобы упростить упаковку, добавьте параметр командной строки -v
v0.9: Если oom_score всех процессов равен 0, используйте VmRss для поиска жертвы.
v0.8: используйте приблизительную оценку, если ядро не предоставляет MemAvailable.
v0.7: выберите жертву по oom_score вместо VmRSS, добавьте опции -i
и -d
v0.6: Добавлены параметры командной строки -m
, -s
, -k
v0.5: Добавлена поддержка свопа.
v0.4: Добавьте сценарий инициализации SysV (спасибо @joeytwiddle), используйте новый MemAvailable
из /proc/meminfo
(требуется Linux 3.14+, зафиксируйте)
v0.2: Добавить файл модуля systemd
v0.1: Начальная версия