← Linux: основы
10 мин · просто · Урок 5 из 8

Процессы и сигналы

PID, ps/top, что значат SIGTERM и SIGKILL, как корректно остановить процесс.

Что такое процесс

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

У каждого процесса есть номер — PID (process id). PID 1 особый: это самый первый процесс, которого запускает ядро при старте системы (обычно systemd). От него деревом расходятся все остальные.

Процессы рождаются не из воздуха: один процесс (родитель) порождает другой (потомок). У потомка есть PPID — PID его родителя. Так получается дерево: терминал запустил твой shell, а shell запускает скрипты, которые ты в нём вызываешь.

Чем смотреть процессы

ps aux                 # снимок всех процессов разом
ps aux | grep nginx    # отфильтровать по имени
top                    # живой монитор, по умолчанию обновляется каждые 3 секунды
htop                   # то же, но удобнее (нужно ставить отдельно)
pgrep -a nginx         # PID-ы по имени + командная строка

Так выглядит вывод ps aux:

$ ps aux
USER   PID %CPU %MEM    VSZ   RSS STAT START  TIME COMMAND
root     1  0.0  0.1 168240 11500 Ss   09:00  0:02 /sbin/init
www     812  1.3  2.4 720160 98400 Sl   09:01  0:21 nginx: worker
deploy 1455  0.0  0.0  12100  3200 R+   10:14  0:00 ps aux

Полезные колонки: PID — номер процесса, %CPU/%MEM — нагрузка, RSS — реально занятая память в КБ, STAT — состояние (R, S, D, Z, T), COMMAND — что запущено. В top сверху видно load average и занятую память.

Состояния процесса (колонка STAT):

Сигналы

Сигнал — асинхронное уведомление, которое ядро (или другой процесс) доставляет процессу. Отправляются командой kill <PID> (несмотря на название, kill — это «послать сигнал», не обязательно убить).

Самые важные три:

СигналНомерЧто значит
SIGTERM15"заверши работу красиво". Сигнал по умолчанию у kill
SIGKILL9"умри немедленно". Процесс не может его перехватить
SIGHUP1"перечитай конфиг" (по соглашению у демонов) или "терминал закрылся"
kill 1234           # послать SIGTERM процессу 1234
kill -9 1234        # послать SIGKILL
kill -HUP 1234      # послать SIGHUP (перечитать конфиг)
pkill nginx         # по имени, а не по PID

Почему kill -9 — последнее средство

SIGTERM процесс может перехватить и обработать: дописать данные на диск, закрыть соединения с БД, корректно завершить запросы, удалить временные файлы. Это называется graceful shutdown.

SIGKILL (-9) перехватить нельзя: ядро убивает процесс мгновенно. Последствия:

Правильный порядок: сначала SIGTERM, подожди (на практике 5–30 секунд, смотря по сервису), и только если процесс завис намертво, шли SIGKILL. Так работают и docker stop, и systemctl stop, только таймауты у них разные.

docker stop даёт 10 секунд, меняется флагом -t. У systemd отсчёт задаёт TimeoutStopSec= в юните, а по умолчанию действует DefaultTimeoutStopSec из /etc/systemd/system.conf, там 90 секунд. Отсюда типичная жалоба «перезапуск сервиса висит полторы минуты»: сервис не отвечает на SIGTERM, и systemd честно ждёт свой таймаут, прежде чем дослать SIGKILL.

Зомби-процессы

Когда процесс завершается, он не исчезает мгновенно: остаётся запись в таблице процессов, пока родитель не "заберёт" его код возврата вызовом wait(). Такой завершённый, но не убранный процесс — зомби (Z в ps).

Зомби не ест ресурсов, он уже мёртв. Занят только номер в таблице. Но если родитель кривой и не делает wait(), зомби копятся и могут забить таблицу PID-ов.

Лечится перезапуском родителя. Когда родитель умирает, его потомков усыновляет процесс с PID 1. Ядро шлёт PID 1 сигнал SIGCHLD, тот делает wait(), и зомби убирается из таблицы.

Фоновые процессы

./long-script.sh &        # запустить в фоне, вернуть управление shell
jobs                      # список фоновых задач текущего shell
fg %1                     # вернуть задачу 1 на передний план

Проблема: фоновый процесс остаётся потомком shell. Закроешь терминал, и shell получит SIGHUP и потянет потомков за собой. Чтобы процесс пережил закрытие сессии:

nohup ./long-script.sh &       # игнорировать SIGHUP, лог в nohup.out
disown %1                       # отвязать уже запущенную задачу от shell

disown — встроенная команда bash/zsh; в dash (это /bin/sh на Debian) её нет, там обходятся nohup и setsid.

На проде для долгоживущих сервисов так не делают: их оформляют как systemd-юнит, который сам следит за процессом и перезапускает при падении. nohup и & годятся для разовых задач.

Что важно запомнить

Процесс = запущенная программа со своим PID. Дерево растёт от PID 1.

Смотреть процессы: ps aux, top/htop, pgrep.

SIGTERM (15) — заверши красиво, SIGKILL (9) — убей насмерть, перехватить нельзя. Сначала TERM, KILL только как крайняя мера.

Зомби — завершённый процесс, которого не убрал родитель. Лечится перезапуском родителя.

Для долгого сервиса нужен systemd-юнит, а не nohup &.

В следующем уроке разберём права доступа: кто и что может делать с файлами.

Когда база уляжется, продолжение в треке «Linux: процессы вглубь»: fork и exec, состояния процессов, зомби и strace.

Дрилл · вопросы как на собесе

Проверь себя без подсказок

Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.

01

Для чего нужны сигналы? Перечисли 5–10 самых частых.

LIN-010
02

Что делает команда kill? Какие сигналы можно слать?

LIN-026
03

В чём разница между Ctrl+C и Ctrl+Z? Какой сигнал получит активный процесс?

LIN-035
04

Как обрабатываются сигналы? Чем SIGTERM отличается от SIGKILL?

LIN-057

Прошли материал до конца? Отметьте урок пройденным.