Процессы в Linux: ps, top, htop, kill, сигналы и nice
Процессы в Linux смотрят командой ps aux (разовый снимок), top и htop (обновляемый список с нагрузкой). Завершают процесс командой kill PID, которая по умолчанию шлёт вежливый SIGTERM; kill -9 (SIGKILL) нужен только если процесс не реагирует. Приоритет задают nice при запуске и renice для уже работающего процесса, в диапазоне от -20 до 19.
Любая запущенная программа в Linux — это процесс с собственным номером PID, владельцем, состоянием и приоритетом. Посмотреть процессы можно командами ps, top и htop, завершить — командой kill, а изменить их приоритет — через nice и renice. Ниже разберём, как читать вывод этих команд, какие сигналы когда отправлять и почему kill -9 не должен быть первым рефлексом.
Что такое процесс и PID
Процесс — это программа в момент выполнения: код, память, открытые файлы и набор атрибутов. Ядро выдаёт каждому процессу уникальный идентификатор PID, а также запоминает PPID — номер родителя, который его запустил. Самый первый процесс в системе с PID 1 — обычно systemd, он и становится «предком» всех остальных.
Новый процесс появляется в два шага. Сначала родитель вызывает fork() и получает свою копию, затем копия вызывает execve() и заменяет свой код кодом новой программы. Когда вы набираете в терминале ls, bash делает именно это и ждёт завершения потомка через wait().
$ echo $$ # PID текущей оболочки
4182
$ ps -o pid,ppid,cmd -p $$
PID PPID CMD
4182 4170 -bash
Как посмотреть процессы командой ps
ps делает разовый снимок: показывает процессы ровно на момент запуска и завершается. Без аргументов он выводит только процессы текущего терминала, поэтому на практике почти всегда используют один из двух вариантов.
$ ps aux | head -5
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.3 168540 12780 ? Ss 09:12 0:03 /sbin/init
root 2 0.0 0.0 0 0 ? S 09:12 0:00 [kthreadd]
www-data 1532 1.2 2.1 412308 86420 ? S 09:15 1:47 php-fpm: pool www
postgres 1610 0.4 3.8 221004 154312 ? Ss 09:15 0:31 postgres: checkpointer
Здесь a — процессы всех пользователей, u — подробный формат с владельцем, x — включая процессы без терминала (демоны). Альтернативный синтаксис в стиле System V — ps -ef: он показывает PPID, что удобно, когда нужно понять, кто кого запустил.
| Колонка | Что означает |
|---|---|
PID | идентификатор процесса |
%CPU, %MEM | доля процессора и физической памяти |
VSZ | виртуальная память в КБ (включая не загруженное в RAM) |
RSS | реально занятая физическая память в КБ |
STAT | состояние процесса (R, S, D, Z, T) и флаги |
TIME | суммарное процессорное время, а не время работы |
Полезные приёмы с ps
# топ-10 по памяти
ps aux --sort=-%mem | head -11
# топ-10 по процессору
ps aux --sort=-%cpu | head -11
# свои колонки
ps -eo pid,ppid,user,ni,stat,etime,cmd
# дерево процессов
ps -ef --forest
pstree -p
# найти PID по имени
pgrep -a nginx
pidof nginx
Классическая ошибка — искать процесс через ps aux | grep nginx и получить в выводе сам grep. Используйте pgrep или трюк grep [n]ginx, который не совпадает с собственной командной строкой.
Состояния процессов: R, S, D, Z, T
Буква в колонке STAT — не мусор, а реальное состояние процесса. От неё зависит, как интерпретировать нагрузку и поможет ли вообще kill.
| Код | Состояние | Что значит на практике |
|---|---|---|
R | Running | выполняется или стоит в очереди на CPU |
S | Interruptible sleep | ждёт события (сеть, ввод, таймер); обычное состояние большинства процессов |
D | Uninterruptible sleep | ждёт ввода-вывода внутри ядра, сигналы не доставляются |
Z | Zombie | завершился, но родитель не забрал код выхода |
T | Stopped | приостановлен сигналом SIGSTOP или Ctrl+Z |
Дополнительные символы после буквы тоже полезны: s — лидер сессии, + — процесс переднего плана в терминале, < — повышенный приоритет, N — пониженный, l — многопоточный.
Процесс в состоянии D
Процесс в D находится внутри системного вызова и ждёт, например, ответа от диска или зависшего NFS. Ему не доставляется ни один сигнал, даже SIGKILL. Поэтому kill -9 тут бесполезен: нужно искать причину ожидания — смотреть iostat, dmesg, состояние сетевого хранилища.
Зомби-процессы
Зомби уже мёртв: он не тратит CPU и память, а занимает только строчку в таблице процессов. Убить его нельзя — он и так завершён. Исчезнет он, когда родитель вызовет wait() или когда сам родитель завершится и зомби «усыновит» PID 1.
# найти зомби и их родителей
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/'
Единичный зомби безвреден. Если их сотни и число растёт, ошибка в родительской программе: её нужно исправить или перезапустить.
top: процессы и нагрузка в реальном времени
top показывает тот же список, но обновляет его каждые несколько секунд и выводит сводку по системе. Это первая команда, которую запускают, когда «сервер тормозит».
top - 14:21:07 up 12 days, 3:02, 2 users, load average: 1.84, 1.20, 0.95
Tasks: 213 total, 2 running, 211 sleeping, 0 stopped, 0 zombie
%Cpu(s): 23.1 us, 4.2 sy, 0.0 ni, 70.3 id, 1.9 wa, 0.0 hi, 0.5 si, 0.0 st
MiB Mem : 7821.4 total, 412.6 free, 3105.8 used, 4303.0 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 4398.2 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1532 www-data 20 0 412308 86420 14212 R 38.2 1.1 1:47.31 php-fpm
1610 postgres 20 0 221004 154312 148900 S 6.0 1.9 0:31.08 postgres
В строке %Cpu(s) важнее всего: us — пользовательский код, sy — ядро, id — простой, wa — ожидание диска. Высокий wa при свободном процессоре — верный признак, что узкое место в вводе-выводе.
Горячие клавиши top
| Клавиша | Действие |
|---|---|
P / M | сортировка по CPU / по памяти |
1 | показать каждое ядро отдельно |
c | полная командная строка |
u | фильтр по пользователю |
k | отправить сигнал процессу |
r | изменить nice процесса |
H | показать потоки |
q | выход |
Для скриптов и логов пригодится пакетный режим: top -b -n 1 | head -20 выведет один снимок без интерактива. Следить за конкретным процессом — top -p 1532.
Load Average — это очередь, а не процент
Три числа load average — средняя длина очереди за 1, 5 и 15 минут. В Linux туда попадают процессы в состояниях R и D, а обычный сон S — нет. Сравнивать LA нужно с числом ядер (nproc): на 4 ядрах значение 4 — полная загрузка, а 12 — очередь втрое больше возможностей.
Если LA высокий, а процессор простаивает, ищите процессы в D: ps -eo stat,pid,cmd | grep '^D'. Почти всегда это медленный диск или сетевое хранилище.
htop: удобная замена top
htop показывает то же самое, но с цветными индикаторами по ядрам, прокруткой, поддержкой мыши и деревом процессов. Обычно его надо установить: sudo apt install htop или sudo dnf install htop.
F3или/— поиск процесса по имени;F4— фильтр, оставляющий только совпадения;F5илиt— дерево «родитель — потомки»;F6— выбор колонки сортировки;F7/F8— уменьшить или увеличить nice;F9— меню сигналов для выбранного процесса;Space— отметить несколько процессов для массового действия.
На серверах без возможности что-то ставить достаточно top: все ключевые операции в нём тоже есть.
Как завершить процесс: kill и сигналы
Команда kill не «убивает», а отправляет процессу сигнал. Что произойдёт дальше, зависит от сигнала и от того, как программа его обрабатывает.
| Сигнал | Номер | Назначение |
|---|---|---|
SIGHUP | 1 | обрыв терминала; многие демоны перечитывают конфиг |
SIGINT | 2 | прерывание, то же, что Ctrl+C |
SIGKILL | 9 | принудительное завершение ядром, перехватить нельзя |
SIGTERM | 15 | просьба завершиться аккуратно; по умолчанию у kill |
SIGSTOP | 19 | приостановить, перехватить нельзя |
SIGCONT | 18 | продолжить приостановленный процесс |
SIGTSTP | 20 | приостановка с терминала, Ctrl+Z |
Номера указаны для x86 и ARM; полный список выводит kill -l. Писать сигнал по имени надёжнее, чем по номеру.
kill 1532 # SIGTERM
kill -TERM 1532 # то же явно
kill -HUP $(pidof nginx) # перечитать конфигурацию
kill -STOP 1532; kill -CONT 1532
kill -0 1532 && echo "процесс жив"
Сигнал 0 ничего не отправляет, а только проверяет, существует ли процесс и есть ли у вас право ему писать, — удобно в скриптах.
Почему не стоит начинать с kill -9
SIGTERM даёт программе шанс закрыть файлы, сбросить буферы, удалить lock-файлы и корректно завершить транзакции. SIGKILL обрывает всё мгновенно: недописанные данные теряются, временные файлы остаются, а база данных при следующем старте может уйти в восстановление.
Правильная последовательность такая:
- Отправить
kill PID(SIGTERM). - Подождать 5–30 секунд, проверяя
kill -0 PID. - Только если процесс жив и не в состоянии
D—kill -9 PID.
Для сервисов под systemd лучше вообще не трогать PID вручную: systemctl stop сам отправит SIGTERM, выждет таймаут и добьёт SIGKILL.
pkill и killall: по имени
pkill -f "python worker.py" # по полной командной строке
pkill -u alice # все процессы пользователя
killall -TERM node # все процессы с именем node
pgrep -l -f worker # сначала проверьте, что попадёт под шаблон
Перед массовым pkill всегда запускайте pgrep с тем же шаблоном: -f совпадает с любой частью командной строки и легко зацепит лишнее.
Отправлять сигналы можно только своим процессам; чужие требуют sudo. Ошибка Operation not permitted означает именно это.
Приоритет процессов: nice и renice
Значение nice подсказывает планировщику, кому уступать процессор. Диапазон — от -20 (самый высокий приоритет) до 19 (уступает всем), по умолчанию 0. В top оно видно в колонке NI, а PR — производный внутренний приоритет.
# запустить тяжёлую задачу с пониженным приоритетом
nice -n 10 tar czf backup.tar.gz /var/www
# понизить приоритет работающего процесса
renice -n 15 -p 1532
# повысить (только root)
sudo renice -n -5 -p 1610
# все процессы пользователя
sudo renice -n 10 -u alice
Обычный пользователь может только понижать приоритет своих процессов, отрицательные значения доступны лишь root. Важно понимать предел nice: он влияет только на CPU. Если задача тормозит систему диском, используйте ionice -c3 команда — класс idle, который получает диск, лишь когда тот никому не нужен.
Фоновые процессы и задания оболочки
Команду можно запустить в фоне, добавив &, или приостановить через Ctrl+Z. Оболочка ведёт список заданий, которыми управляют встроенные команды.
$ long_task &
[1] 5120
$ jobs
[1]+ Running long_task &
$ fg %1 # вернуть на передний план
^Z # приостановить (SIGTSTP)
$ bg %1 # продолжить в фоне
При закрытии терминала оболочка шлёт заданиям SIGHUP, и они завершаются. Чтобы процесс пережил выход, запускайте его через nohup команда &, отвязывайте командой disown или используйте tmux. Для постоянной работы правильнее оформить его как сервис systemd.
Типичные сценарии диагностики
Кто съел процессор
top -o %CPU # или P внутри top
ps -eo pid,user,%cpu,etime,cmd --sort=-%cpu | head
Если процесс жрёт CPU без пользы, сначала понизьте ему приоритет через renice — это безопасно и даёт время разобраться.
Кто занял порт
sudo ss -ltnp | grep :8080
sudo lsof -i :8080
В выводе будет PID, а дальше по нему в /proc/PID/ можно найти исполняемый файл (exe), рабочий каталог (cwd) и аргументы (cmdline).
Процесс неожиданно исчез
Частая причина — OOM Killer, который убивает процессы при нехватке памяти. Проверка: dmesg -T | grep -i oom или journalctl -k | grep -i "killed process".
Итог
Для работы с процессами в Linux хватает небольшого набора команд: ps aux для снимка, top и htop для наблюдения, kill с правильным сигналом для завершения и nice/renice для приоритетов. Читайте состояние процесса прежде чем действовать: зомби и процессы в D сигналами не лечатся. И начинайте с SIGTERM, оставляя kill -9 на крайний случай. Процессы, память, Load Average и системные вызовы подробно разобраны на практике в курсе по Linux.
Частые вопросы
Чем ps aux отличается от ps -ef?
Это два синтаксиса одной команды: aux — BSD-стиль с колонками %CPU, %MEM и STAT, -ef — стиль System V с колонкой PPID. Набор процессов в обоих случаях один и тот же — все процессы системы.
Как узнать, сколько процессов запущено в системе?
Проще всего посмотреть строку Tasks в top или выполнить ps -e --no-headers | wc -l. Число потоков покажет ps -eLf --no-headers | wc -l.
Почему процесс не завершается даже после kill -9?
Либо он в состоянии D и ждёт ввода-вывода в ядре, либо это зомби, который уже завершён. В первом случае ищите проблему с диском или сетевым хранилищем, во втором — исправляйте или перезапускайте родителя.
Что будет, если убить процесс с PID 1?
Ядро защищает init: обычные сигналы, включая SIGKILL от пользователя, ему не доставляются, если он их не обрабатывает. Если же init всё-таки завершится, система уйдёт в kernel panic.
Как ограничить процессу использование памяти?
Для сервиса systemd задайте MemoryMax= в unit-файле, для разового запуска — systemd-run --scope -p MemoryMax=500M команда. Это работает через cgroups и надёжнее старого ulimit -v.
Эта тема подробно разобрана с практикой в курсе «Linux: с нуля до уверенного администрирования».
Перейти к курсу