🐹 CentOS 7: Процессы. Сигналы. Команды. Подробная информация о процессе PID. Убиваем процессы PID — команды ps, kill, pkill, killall, xkill. Потребление ресурсов процессами — утилита top.

Содержание:

1. Введение.
2. Команды и сигналы kill.
3. Не используйте kill -9.

3.1. Проблемы, возникающие при завершении процессов.
3.2. Сигналы завершения процесса.

4. Находим PID зависшего процесса.

4.1. Ключи и описания.

5. «Убиваем» процесс командой kill.
6. «Убиваем» процесс командой pkill.
7. Убиваем процессы командой killall.
8. Убиваем процессы командой xkill.
9. Если что-то пошло не так.
10. Вызов справки.
11. Подробная информация о процессе.
12. Потребление ресурсов процессами — top.
13. Оригиналы источников информации.


1. Введение.

В Linux существуют процессы и сигналы с помощью которых процессы могут взаимодействовать между собой.

Под процессом мы будем понимать запущенную в системе копию программы.

Например, если вы открыли три окна калькулятора (например, gcalctool), это значит, что вы запустили три процесса.

Сигнал — (signal) — это программные прерывания, посылаемые в (запущенную) программу для указания на то, что произошло важное событие.

Для управления процессами существует такая подсистема как менеджер процессов.

В Linux реализована многозадачность с вытеснением и менеджер процессов полностью управляет процессами.

Каждый процесс имеет свой контекст.

Контекст процесса — это таблица распределения памяти, текущий статус процесса, приоритет процесса, данные о используемых ресурсах, маска сигналов, идентификаторы процесса и другие свойства.

Идентификатор процесса состоит из идентификатора PID и идентификатора родительского процесса PPID.

Первый пользовательский процесс называется init. Его PID всегда равен 1, а PPID равен 0, так как он не имеет родительского процесса, а порождается ядром на определенном этапе загрузки системы.

Все остальные процессы являются дочерними процессами и имеют PPID отличный от нуля.

Для того чтобы породить новый процесс, родительский вызывает функцию ядра fork(), в результате которой происходит клонирование родительского процесса и получается абсолютно одинаковый процесс на начальном этапе. Единственное отличие: у дочернего процесса увеличивается PID.

PID дочернего процесса всегда будет больше чем у родительского. В остальном контекст полностью будет совпадать с родительским.

Затем для дочернего процесса запускается функция exec(), которая начинает уже изменять контекст на нужный, загружать в память код программы и так далее.

Операционная система Linux является еще и многопользовательской.

У каждого процесса есть такой параметр как “владелец” — от имени которого выполняется процесс. Это UID процесса. Также у процесса есть такой параметр как GID (по аналогии с GID пользователя). Кроме этого есть такие параметры как EUID (эффективный UID) и EGID (эффективный GID). Возможности процесса в системе определяются именно этими параметрами: EUID и EGID.

EUID = UID пользователя, если бит setuid = 0.
EUID = UID программы, если бит setuid = 1.

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

nice-фактор — это числовое значение. Чем оно больше тем меньше ресурсов (процессорного времени и так далее) будет выделятся процессу во время его работы.

Многие процессы выполняют операции ввода/вывода информации в/из терминала. Поэтому есть такой параметр как Терминал.

А есть процессы которые работают в фоновом режиме. Такие процессы не привязаны к терминалу. Например, процесс cron.

Процесс может находится в нескольких состояниях:

  1. Выполнение — менеджер процессов выделил все необходимые ресурсы и процесс просто ждет своей очереди на получение следующей порции процессорного времени.
  2. Ожидание — процесс получил все ресурсы, но для продолжения работы он ждет какую-то информацию, например, от другого процесса.
  3. Остановленный — процесс ничего не делает, процессорное время не получает. Процесс был переведен в это состояние с помощью специальных сигналов и выйти из этого состояния может также только с помощью соответствующего сигнала.
  4. Зомби” — это процесс который должен был завершиться с освобождением всех ресурсов, но по какой-то причине завершение не произошло корректно. С процессами “Зомби” нужно быть осторожными. Если таких процессов много значит в системе что-то не так.

Для просмотра процессов и их свойств предназначена команда ps.

Команда имеет очень много ключей и параметров. Все их можно посмотреть в man ps.

2. Команды и сигналы kill.

Это связано с Signals (сигналами).

Один процесс при помощи ядра может передать другому процессу специальное числовое значение сигнала. Процесс вызывает функцию передачи сигнала и передает необходимую информацию (код сигнала, PID процесса) ядру. Ядро передает сигнал процессу получателю и отслеживает как этот сигнал обрабатывается. Сигналы обозначаются цифрами или мнемоническими обозначениями.

Когда вы выполняете команду kill, то фактически вы посылаете системе сигнал, чтобы заставить ее завершить некорректно ведущее себя приложение.

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

Существует несколько типов сигналов, которые мы можем использовать — чтобы получить полный список всех доступных / возможных сигналов, используйте команду:

# kill -l

Ответ:

Всего вы можете использовать до 60 сигналов, но все, что нужно знать, это SIGTERM (15) и SIGKILL(9).

SIGTERM — этот сигнал запрашивает остановку работы процесса. Он может быть проигнорирован. Процессу дается время на корректное завершение. Если программа завершается корректно, значит она использовала данное время на то, чтобы сохранить свое состояние или результаты работы и освободить ресурсы. Другими словами, ее не заставляли остановиться.

SIGKILL — этот сигнал заставляет процесс прекратить работу немедленно. Программа не может проигнорировать этот сигнал. Несохраненные результаты будут потеряны.

Мнемонические имена которые вы видите (SIGTERM , SIGINT, SIGKILL) начинаются с приставки SIG. Имена в этом виде используются в языках программирования таких как С. В интерпретаторе bash используются или числа или мнемонические имена, но без приставки SIGTERM, INT, KILL.

Часть сигналов (INT, TERM) являются перехватываемыми. Это означает, что процесс при получении такого сигнала должен перейти на специальную подпрограмму, которая занимается обработкой сигнала. Если подпрограммы обработки нет (а ее написанием занимаются разработчики программы, которая выполняется в контексте процесса), то управление передается ядру, которое выполняет действия по умолчанию, описанные для каждого сигнала.

Часть сигналов являются такими которые можно заблокировать. Например, один процесс посылает сигнал TERM другому процессу, а он в свою очередь не закончил операции ввода/вывода. В таком случае второй процесс может заблокировать полученный сигнал (опять таки в обработчике сигнала) до момента выполнения необходимой операции ввода/вывода. Сигнал TERM — это сигнал корректного завершения работы процесса. Обработчик этого сигнала, должен выполнить все необходимые действия для правильного завершения работы.

И есть третья группа сигналов, которые не блокируются и для которых не нужны обработчики. Примером такого сигнала является сигнал kill. Этот сигнал уничтожает процесс, так как для него нет обработчиков в процессах, то он будет обрабатываться ядром по умолчанию и так как он не блокируемый, то действия будут выполнятся немедленно.

Пока мы говорили о том как процессы “общаются” между собой с помощью сигналов. Но мы (пользователи) также можем посылать сигналы процессам. Например, комбинация клавиш Ctrl+C посылает процессу сигнал INT, который прерывает выполнение процесса. Если вы наберете в терминале команду sleep 100, то команда не вернет управление терминалу пока не завершится. Прервать выполнение этой команды можно нажав комбинацию клавиш Ctrl+C.

В чем же отличия между похожими сигналами INT, TERM, KILL (а также QUIT и HUP)?

Несмотря на похожесть отличия есть:

Сигнал KILL не блокируется и не перехватывается и ведет к немедленному завершению процесса.

Сигнал INT в отличии от killявляется блокируемым сигналом и перехватываемым.

Сигнал TERM также является перехватываемым и блокируемым и предназначен для корректного (предпочтительного) завершения работы процесса.

Сигнал QUIT — похож на TERM, но позволяет сохранить дамп памяти.

Сигнал HUP — сейчас этот сигнал чаще всего интерпретируется процессами как “прочесть конфигурационные файлы”.

Синтаксис использования «kill»:

# kill [сигнал или опция] PID

Сигнал по умолчанию (если он не задан) — SIGTERM.

Если он не помогает, для принудительного завершения процесса можно использовать следующие варианты:

# kill SIGKILL PID
# kill -9 PID

где флаг -9 ссылается на сигнал SIGKILL .

Также обратите внимание, что можно завершать несколько процессов одной командой.

# kill -9 PID1 PID2 PID 3

3. Не используйте kill -9.

Аргумент -9 (или kill) для команды kill следует использовать только в случае крайней необходимости.

Почему?

Единственный сигнал который приложение «не имеет право» перехватывать это -9 (kill).

Сигнал kill не может быть обработан процессом. Это означает, что после завершения процесса с помощью kill -9, дочерние процессы останутся в памяти и станут «осиротевшими» (orphaned), файловая система окажется засорена временными файлами, сегменты совместно используемой памяти — активными, сокеты — зависшими, а функция atexit(3) вообще не будет выполнена. В результате есть риск столкнуться с неожиданными и сложными для отладки проблемами.

Вместо этого используйте дефолтный сигнал TERM, а kill— только если менее проблемные сигналы окажутся неэффективными:

# kill 6738
# kill -INT 6738
# kill -HUP 6738
# kill -KILL 6738

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

Использование kill -KILL по умолчанию допустимо при работе с проблематичным приложением, например, старые версии Netscape частенько завершались только с помощью сигнала kill.

Однако, это редкое исключение из правила: используйте kill для этих заранее известных приложений и только для них.

3.1. Проблемы, возникающие при завершении процессов.

Последовательная отправка разных сигналов может вызвать следующие проблемы: во-первых, процессу могут потребоваться секунды, или даже десятки секунд для корректного завершения.

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

Во-вторых, иногда бывают ситуации, когда старый процесс завершился, в то время как новый процесс занял его ID в промежутке между сигналами TERM и KILL. Особенно этому риску подвергаются системы с повышенной «текучкой» процессов и системы, где ядро назначает PID в случайном порядке, например, OpenBSD.

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

3.2. Сигналы завершения процесса.

Сигналы завершения процесса могут обозначаться по имени или порядковому номеру: kill -1 PID и kill -HUP эквивалентны, kill -15 PID и kill -TERM эквивалентны.

kill PID (-15 или -TERM используются по умолчанию). Если же этот вариант не помог, попробуйте убить процесс, посылая сигналы в порядке «силы», как описано в статье, учитывая, что процессу может потребоваться некоторое время для корректного завершения.

Однако, использование имени сигнала более безопасно, так как при указании аргумента -1 легко опечататься, отправив сигнал другому процессу или даже группе процессов.

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

Сигнал HUP «подвешивает» шелл, поэтому это хороший способ очистить шелл, повисший в ожидании ввода, или закрыть SSH-сессию.

4. Находим PID зависшего процесса.

Рассмотрим, как использовать команды, находить PID процесса и посылать сигнал SIGKILL.

Каждый процесс в Linux имеет свой идентификатор, называемый PID. Перед тем, как выполнить остановку процесса, нужно определить его PID. Для этого воспользуемся командами ps и grep. Команда ps предназначена для вывода списка активных процессов в системе и информации о них. Команда grep запускается одновременно с ps (в канале) и будет выполнять поиск по результатам команды ps.

Вывести на экран список текущих процессов, запущенных пользователем, можно командой:

# ps

Вывести список всех процессов можно, выполнив в командной строке:

# ps axu

где:

  • USER — учетная запись пользователя, от которой запущен процесс.
  • PID — идентификатор процесса.
  • %CPU — потребление процессорного времени в процентном эквиваленте.
  • %MEM — использование памяти в процентах.
  • VSZVirtual Set Size. Виртуальный размер процесса (в килобайтах).
  • RSSResident Set Size. Размер резидентного набора (количество 1K-страниц в памяти).
  • TTY — терминал, из под которого был запущен процесс.
  • STAT — текущее состояние процесса. Могут принимать значения:
    1. R — выполнимый процесс;
    2. S — спящий;
    3. D — в состоянии подкачки на диске;
    4. T — остановлен;
    5. Z — зомби;
    6. W — не имеет резидентных страниц;
    7. < — высоко-приоритетный;
    8. N — низко-приоритетный;
    9. L — имеет страницы, заблокированные в памяти.
  • START — дата запуска процесса.
  • TIME — время запуска процесса.
  • COMMAND — команда, запустившая процесс.

Чтобы увидеть информацию о nice-факторе необходимо выполнить команду ps lax:

# ps lax

Ответ:

Особый интерес для нас предоставляют следующие столбцы:

  • PPID — отображен PID родительского процесса. Например для первой строки примера PPID равен 1, значит родительским для этого процесса является процесс init. Процесс из третьей строки является дочерним процесса из второй строки и так далее.
  • NI — значение nice-фактора.
  • PRI — приоритет процесса.

4.1. Ключи и описания.

-A — Все процессы.
-a — Запущенные в текущем терминале, кроме главных системных.
-d — Все, кроме главных системных процессов сеанса.
-e — Все процессы.
f — Показать дерево процессов с родителями.
T — Все на конкретном терминале.
a — Все, связанные с текущим терминалом и терминалами других пользователей.
r — Список только работающих процессов.
x — Отсоединённые от терминала.
u — Показать пользователей, запустивших процесс.

Но, как правило, список очень большой и найти процесс, который мы хотим «убить», бывает не так просто. Здесь на помощь приходит команда grep.

Чтобы было что закрывать запустим диспетчер задач top в фоновом режиме с помощью & на конце команды запуска:

# top &

И еще раз

# top &

Например, чтобы найти информацию о процессе с именем top выполните команду:

# ps axu | grep top

Команда grep выполнит поиск по результатам команды ps и на экран будут выведены только те строки, которые содержат строку (слово) top.

Здесь есть одна интересная деталь, например, если у вас не запущено приложение калькулятора для графической оболочки gcalctool, то после выполнения ps axu | grep gcalctool вы получите:

# ps axu | grep gcalctool

То есть мы получили сам процесс grep, так как в качестве параметра команде мы указали слово gcalctool, и grep нашел сам себя в выводе команды ps.

Если процесс top запущен 2 раза подряд, то мы получим:

# ps axu | grep top

К примеру здесь нас интересует строка: «root 19703 0.0 0.0 159368 1776 pts/0 T 01:04 0:00 top». Число 19703 и есть идентификатор (PID) процесса top. И вторая строка, соответственно, 19750 тоже принадлежит другому процессу top.

Есть еще один более простой способ узнать PID процесса — это команда pidof, которая принимает в качестве параметра название процесса и выводит его PID.

Пример выполнения команды pidof:

# pidof top

5. «Убиваем» процесс командой kill.

Когда известен PID процесса, мы можем убить его командой kill. Команда kill принимает в качестве параметра PID процесса.

Например, убьем процессы с номером 19750 и номером 19703:

# kill 19750
# kill 19703

Проверим, закрылись ли они?

# ps axu | grep top

Как видно они не закрылись!

Вообще команда kill предназначена для посылки сигнала процессу. По умолчанию, если мы не указываем какой сигнал посылать, посылается сигнал SIGTERM (от слова termination — завершение). SIGTERM указывает процессу на то, что необходимо завершиться. Каждый сигнал имеет свой номер. SIGTERM имеет номер 15.

Список всех сигналов (и их номеров), которые может послать команда kill, можно вывести, выполнив kill -l.

# kill -l

Чтобы послать сигнал SIGKILL (он имеет номер 9) процессу 19703 и процессу 19750, выполните в командой строке:

# kill -9 19703

Ищем процесс по имени, извлекаем его PID и завершаем его:

# kill `ps aux | grep 'top' | awk '{print $2}'`

Обратите внимание, что запрос может вывести несколько процессов, которые будут попадать под критерии поиска — в таком случае, они будут завершены все.

Проверим, закрылись ли они?

# ps axu | grep top

То есть мы получили сам процесс grep, так как в качестве параметра команде мы указали слово top, и grep нашел сам себя в выводе команды ps.

Сигнал SIGTERM может и не остановить процесс (например, при перехвате или блокировке сигнала), SIGKILL же выполняет уничтожение процесса всегда, так как его нельзя перехватить или проигнорировать.

Если процесс не завершается, убиваем его принудительно:

# kill -9 PID

6. «Убиваем» процесс командой pkill.

Команда «pkill» позволяет использовать расширенные шаблоны регулярных выражений и другие критерии соответствия. Вместо использования PID вы теперь можете завершить приложение, введя имя его процесса. Например, для завершения работы Firefox просто введите команду:

# pkill firefox

Так как оно соответствует шаблону регулярного выражения, вы можете также ввести имя только частично, например:

# pkill fire

Чтобы предотвратить завершение не тех приложений, которые требовалось, можно использовать команду «pgrep -l [process name]» для вывода списка всех подходящих процессов.

# pgrep -l nginx

Ответ:

7. Убиваем процессы командой killall.

Команда kill довольно ограничена в возможностях и не позволяет выполнять более сложные действия. Поэтому рассмотрим еще одну команду — killall.

Команда killall в Linux предназначена для «убийства» всех процессов, имеющих одно и то же имя. Это удобно, так как нам не нужно знать PID процесса.

7.1. В этой ситуации рекомендуется выйти из системы и завершить все запущенные процессы пользователя с помощью команды killall:

# sudo killall -u username

7.2. Основное преимущество этой команды, то что она умеет посылать сигналы всем процессам с одинаковым именем или всем процессам одного пользователя.

Например, мы хотим закрыть все процессы с именем top.

Выполните в терминале:

# killall top

или nginx:

# killall nginx

7.3. Команда killall, также как и kill, по умолчанию шлет сигнал SIGTERM. Чтобы послать другой сигнал нужно воспользоваться опцией -s.

Например:

# killall -s 9 top

Как и в случае с kill, можно это сделать принудительно:

# killall -9 nginx

7.4. Если запустить команду killall c ключом -i, то перед посылкой сигнала будет запрашиваться подтверждение:

# killall -i nginx

8. Убиваем процессы командой xkill.

Xkill — это графический способ завершения приложений.

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

Если вам понравится такой способ, можно настроить для активации xkill горячие клавиши.

9. Если что-то пошло не так.

Некоторые процессы не удается остановить под обычным пользователем.

Например, если процесс был запущен от имени пользователя root или от имени другого пользователя системы, то команды kill и killall нужно выполнять от имени суперпользователя, добавляя sudo:

# sudo kill 123

Бывают ситуации, когда вы работаете в графическом интерфейсе (например, GNOME) и вам не удается открыть эмулятор терминала, чтобы остановить зависший процесс. Тогда можно переключиться на виртуальную консоль клавишами Ctrl+Alt+F1, залогиниться в ней и выполнять команды уже из нее, а потом перейти обратно, нажав Ctrl+Alt+F7.

10. Вызов справки.

Справку по использованию любой команды можно получить командой man:

# man ps
# man grep
# man pidof
# man kill
# man killall

11. Подробная информация о процессе.

Для каждого процесса создается каталог по пути /proc/<PID>, в котором создаются папки и файлы с описанием процесса.

11.1. Подробный вывод статуса:

# cat /proc/<PID>/status

Ответ:

11.2. Адрес в ячейках оперативной памяти, которые занял процесс:

# cat /proc/<PID>/syscall

Ответ:

11.3. Команда, которой был запущен процесс:

# cat /proc/<PID>/cmdline

Ответ:

11.4. Символьная ссылка на рабочий каталог процесса:

# ll /proc/<PID>/cwd

Ответ:

11.5. Символьная ссылка на исполняемый файл, запустивший процесс:

# ll /proc/<PID>/exe

Ответ:

Увидеть ссылки на дескрипторы открытых файлов, которые затрагивает процесс:

# ll /proc/<PID>/fd/

Ответ:

Подробное описание на сайте man7.org.

12. Потребление ресурсов процессами — top.

Для просмотра статистики потребления ресурсов используем утилиту top:

# top

Пример вывода:

где:

  • PID — идентификатор процесса.
  • USER — имя учетной записи, от которой запущен процесс.
  • PR — приоритет процесса.
  • NI — приоритет, выставленной командой nice.
  • VIRT — объем виртуальной памяти, потребляемый процессом.
  • RES — объем используемой оперативной памяти.
  • SHR — количество разделяемой памяти, которое используется процессом.
  • S — состояние процесса.
  • %CPU — процент использования процессорного времени.
  • %MEM — потребление оперативной памяти в процентах.
  • TIME — использование процессорного времени в секундах.
  • COMMAND — команда, которая запустила процесс.

13. Оригиналы источников информации.

  1. pingvinus.ru «Убиваем процессы в Linux — команды ps, kill и killall».
  2. dmosk.ru «Работа с процессами в Linux».
  3. man7.org «proc(5) — Linux manual page».
  4. stackoverflow.com «Why number 9 in kill -9 command in unix?»
  5. igorka.com.ua «Лекция №13 Сигналы в Linux».
  6. habr.com «Не используйте kill -9».
  7. rus-linux.net «Осваиваем команду Kill в Linux».

Читайте также: