Как быстро остановить процесс, вызывающий перебои (из-за избыточного выделения памяти)?


19

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

Я недавно испытал это на своем ноутбуке Ubuntu из-за сценария Matlab, пытающегося выделить смехотворно огромную матрицу. После ~ 5 + минут разгрома я смог Ctrl-F1 к консоли и убить Matlab. Я бы предпочел иметь какую-нибудь горячую клавишу, которая сразу же дала бы мне контроль над системой и позволила бы мне убить процесс оскорбления; или, может быть, просто молча откажитесь выделить такой большой буфер.

  1. Каков самый быстрый способ восстановить контроль над системой Linux, которая перестала отвечать или стала очень вялой из-за чрезмерной подкачки?

  2. Существует ли эффективный способ предотвратить такой обмен в первую очередь, например, путем ограничения объема памяти, который процессу разрешено пытаться выделить?

Ответы:


12

Нажмите Alt-SysRq-F, чтобы завершить процесс, используя больше памяти:

  • Клавиша SysRq обычно сопоставляется клавише Print.
  • Если вы используете графический рабочий стол, вам может потребоваться нажать Ctrl-Alt-SysRq-F в случае, если нажатие Alt-SysRq запускает другое действие (например, программу моментального снимка).
  • Если вы используете ноутбук, вам, возможно, придется нажать функциональную клавишу.
  • Для получения дополнительной информации прочитайте статью в Википедии .

5

Я сделал скрипт для этой цели - https://github.com/tobixen/thrash-protect

Этот сценарий успешно работает на производственных серверах, рабочих станциях и ноутбуках. Этот сценарий не убивает процессы, но временно приостанавливает их - позже у меня было несколько ситуаций, в которых я совершенно уверен, что потерял контроль из-за сбоя, если бы не этот простой сценарий. В «худшем» случае нарушающий процесс будет сильно замедлен и, в конце концов, будет убит ядром (OOM), в «лучшем» случае вызывающий процесс фактически завершится ... в любом случае, на сервере или рабочей станции останется относительно отзывчивым, чтобы можно было легко исследовать ситуацию.

Конечно, «купить больше памяти» или «не использовать своп» - это два альтернативных, более традиционных ответа на вопрос «как избежать перебора?», Но в целом они, как правило, работают не так хорошо (установка большего объема памяти может Будучи нетривиальным, мошеннический процесс может поглотить всю память независимо от того, сколько у него установлено, и вы можете столкнуться с проблемами перебивания даже без подкачки, когда не хватает памяти для буферизации / кэширования). Я рекомендую защиту от трэша плюс много места подкачки.


Что касается отключения свопа, то, по мнению unix.stackexchange.com/a/24646/9108, это может быть не лучшим вариантом.
sashoalm

На самом деле, кто-то так прокомментировал меня, поэтому я изменил документ по защите от трэша.
Тобиксен

4
  1. Каков самый быстрый способ восстановить контроль над системой Linux, которая перестала отвечать или стала очень вялой из-за чрезмерной подкачки?

Уже ответил выше с Alt-SysRq-F

  1. Существует ли эффективный способ предотвратить такой обмен в первую очередь, например, путем ограничения объема памяти, который процессу разрешено пытаться выделить?

Я отвечаю на эту 2-ую часть. Да, ulimitвсе еще работает достаточно хорошо, чтобы ограничить один процесс. Вы можете:

  • установить мягкое ограничение для процесса, который, как вы знаете, скорее всего выйдет из-под контроля
  • установить жесткий лимит для всех процессов, если вы хотите дополнительную страховку

Также, как кратко сказано:

Вы можете использовать CGroups для ограничения использования ресурсов и предотвращения таких проблем

Действительно, cgroups предлагает более продвинутый контроль, но в настоящее время, по моему мнению, его сложнее настроить.

Старая школа ulimit

Один раз

Вот простой пример:

$ bash
$ ulimit -S -v $((1*2**20))
$ r2(){r2 $@$@;};r2 r2
bash: xmalloc: .././subst.c:3550: cannot allocate 134217729 bytes (946343936 bytes allocated)

Это:

  • Устанавливает мягкое ограничение общего использования памяти в 1 ГБ (ulimit предполагает ограничение в единицах кБ)
  • Запускает рекурсивный вызов функции bash r2(){ r2 $@$@;};r2 r2, который экспоненциально нагружает ЦП и ОЗУ, бесконечно удваивая себя при запросе стековой памяти.

Как видите, он остановился при попытке запросить более 1 ГБ.

Обратите внимание, -vработает с распределением виртуальной памяти (всего, то есть физической + подкачки).

Постоянная защита

Чтобы ограничить выделение виртуальной памяти, asэто эквивалент -vдля limits.conf.

Я делаю следующее, чтобы защитить себя от любого неправильного поведения:

  • Установите жесткое ограничение адресного пространства для всех процессов.
  • address space limit = <physical memory> - 256MB,
  • Следовательно, ни один процесс с использованием жадной памяти или активной петли и утечки памяти не может потреблять ВСЕ физическую память.
  • Запас 256 Мбайт для существенной обработки с помощью SSH или консоли.

Один лайнер:

$ sudo bash -c "echo -e \"*\thard\tas\t$(($(grep -E 'MemTotal' /proc/meminfo | grep -oP '(?<=\s)\d+(?=\skB$)') - 256*2**10))\" > /etc/security/limits.d/mem.conf"

Для проверки это приводит к следующему (например, в системе 16 ГБ):

$ cat /etc/security/limits.d/mem.conf
*   hard    as      16135196
$ ulimit -H -v
161351960

Примечания:

  • Только смягчает против одного процесса, идущего за борт с использованием памяти.
  • Не предотвратит многопроцессорную рабочую нагрузку с большой нагрузкой на память, вызывающей побои (тогда ответом будет cgroups).
  • Не используйте rssопцию в limit.conf. Это не соблюдается новыми ядрами.
  • Это консервативно.
    • Теоретически, процесс может спекулятивно запрашивать много памяти, но только активно использовать подмножество (меньшее использование рабочего набора / резидентное использование памяти).
    • Вышеуказанное жесткое ограничение приведет к тому, что такие процессы будут прерваны (даже если они могли бы нормально работать, учитывая, что Linux допускает перегрузку адресного пространства виртуальной памяти).

Более новые CGroups

Предлагает больше контроля, но в настоящее время более сложный в использовании:

  • Улучшает предложение ulimit.
    • memory.max_usage_in_bytes может учитывать и ограничивать физическую память отдельно.
    • Принимая во внимание , ulimit -mи / или rssв limits.confпредназначалось , чтобы предложить подобную функциональность, но это не работает , так как ядро Linux 2.4.30!
  • Нужно включить некоторые ядра контрольной группы флагов в загрузчике: cgroup_enable=memory swapaccount=1.
    • Это не произошло по умолчанию с Ubuntu 16.04.
    • Вероятно, из-за некоторых последствий для производительности дополнительных накладных расходов.
  • Материал cgroup / systemd является относительно новым и немного меняющимся, поэтому поток вверх по течению подразумевает, что производители дистрибутивов Linux еще не сделали его простым в использовании. Между 14.04LTS и 16.04LTS изменился инструментарий пользовательского пространства для использования cgroups.
    • cgm теперь кажется официально поддерживаемым инструментом для пользователей.
    • Похоже, что в системных файлах юнитов пока нет предопределенных значений по умолчанию "vendor / distro", чтобы расставить приоритеты для важных сервисов, таких как ssh.

Например, чтобы проверить текущие настройки:

$ echo $(($(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes) / 2**20)) MB
11389 MB
$ cat /sys/fs/cgroup/memory/memory.stat
...

Например, чтобы ограничить память одного процесса:

$ cgm create memory mem_1G
$ cgm setvalue memory mem_1G memory.limit_in_bytes $((1*2**30))
$ cgm setvalue memory mem_1G memory.memsw.limit_in_bytes $((1*2**30))
$ bash
$ cgm movepid memory mem_1G $$
$ r2(){ r2 $@$@;};r2 r2
Killed

Чтобы увидеть это в действии, пережевывающее ОЗУ как фоновый процесс и затем убитое:

$ bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2' & while [ -e /proc/$! ]; do ps -p $! -o pcpu,pmem,rss h; sleep 1; done
[1] 3201
 0.0  0.0  2876
 102  0.2 44056
 103  0.5 85024
 103  1.0 166944
 ...
98.9  5.6 920552
99.1  4.3 718196
[1]+  Killed                  bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2'

Обратите внимание на экспоненциальный (степень 2) рост количества запросов памяти.

Будем надеяться, что в будущем «дистрибутив / вендоры» предварительно сконфигурируют приоритеты и ограничения cgroup (через модули systemd) для таких важных вещей, как SSH и графический стек, чтобы они никогда не испытывали недостатка памяти.


2

Вы можете нажать Ctrl- zчтобы приостановить программу. Затем вы можете сделать kill %1(или любой другой номер работы, или вы можете использовать PID).

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


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

Вы можете запустить, kill -STOP <pid>который будет делать то же самое, что Ctrl-Z.
hlovdal

Да, но вся проблема в том, что в такой ситуации система настолько не реагирует на запросы, что требуется много времени (или навсегда), чтобы добраться до командной строки.
nibot

1

Вы можете использовать CGroups для ограничения использования ресурсов и предотвращения таких проблем: https://en.wikipedia.org/wiki/Cgroups


Пожалуйста, включите необходимую информацию в свой ответ и используйте ссылку только для указания авторства и дальнейшего чтения. Эта ссылка описывает, что такое CGroups, но из ссылки не очевидно, как на самом деле использовать ее для решения проблемы. Можете ли вы расширить свой ответ, чтобы описать решение вопроса? Благодарю.
fixer1234

0

Было бы неплохо, если бы в графическом интерфейсе была горячая клавиша для отправки SIGSTOP в любое приложение, на которое была сфокусирована!

Всегда есть классическая xkillкоманда (из xorg-x11-apps-7.4-14.fc14.src.rpm в моей системе). Я предполагаю, что не должно быть слишком сложно создать клон, который посылает SIGSTOP вместо того, чтобы убивать целевое окно.


Как я могу быстро запустить xkill нажатием какой-либо комбинации клавиш?
nibot

Я не уверена. Я предполагаю, что и gnome, и KDE имеют некоторые глобальные функциональные возможности быстрого доступа, которые можно использовать для запуска программ.
Хловдал
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.