Тулзы для процессов — ps, pgrep, kill, /proc
В предыдущих уроках мы разобрали, как процессы устроены и как живут. Теперь — инструментарий: как смотреть, искать, управлять процессами в практической работе. Эти инструменты вы будете использовать каждый день: дебажить «почему сервис не отвечает», искать «кто съел всю память», отправлять сигналы перезагрузить конфиг.
В этом уроке — глубокое погружение в ps, pgrep, kill, pstree, и работу с /proc/[pid]/. После урока вы должны уверенно ориентироваться в любой системе и за минуту понимать, что в ней происходит.
ps: швейцарский нож для процессов
ps — самый базовый инструмент. У него тяжёлая история: он поддерживает три разных синтаксиса (BSD, SysV, GNU long options). Это часто путает. Запомните несколько проверенных вариаций.
Часто используемые варианты
# Простой список процессов в системе (SysV style):
ps -ef
# UID PID PPID C STIME TTY TIME CMD
# То же, но BSD style:
ps aux
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# Дерево процессов:
ps -ejH # тоже самое в формате SysV
ps axjf # BSD
# Конкретный пользователь:
ps -u username
ps -U username # реальный UID, а не effective
# Конкретные процессы по имени:
ps -C nginx # точное имя
ps -fp 1234 # по PID, полные поля
# Mои процессы:
ps -ef -u $(id -u)
Кастомный вывод колонок
Самый мощный режим — ps -eo, где вы сами выбираете столбцы:
ps -eo pid,user,uid,nice,pri,rss,vsz,wchan,stat,start_time,cmd --sort=-rss | head -10
Что значат колонки:
Полезные сценарии ps
# Топ-10 процессов по памяти:
ps -eo pid,user,rss,vsz,cmd --sort=-rss | head -10
# Топ-10 по CPU (накопительному):
ps -eo pid,user,%cpu,%mem,cmd --sort=-%cpu | head -10
# Все процессы, которые в состоянии D (uninterruptible):
ps -eo stat,pid,wchan,cmd | awk '$1 ~ /^D/'
# Все zombies:
ps -eo stat,pid,ppid,cmd | awk '$1 ~ /^Z/'
# Процессы с большим nice (низкий приоритет):
ps -eo pid,nice,cmd | awk '$2 > 0'
# Сколько потоков у процесса:
ps -o nlwp= -p 1234
# Все процессы с одного PPID (одного родителя):
ps -ef | awk '$3 == "1234"'
top и htop: интерактивный мониторинг
ps — статический снимок. Для реального времени — top (всегда есть) или htop (улучшенный, надо ставить).
# Базовый top:
top
# С обновлением каждые 0.5 секунды:
top -d 0.5
# Только конкретного пользователя:
top -u username
# Сортировка по памяти:
top -o RES # или нажмите M внутри top
# Один снимок без интерактивности (для скриптов):
top -bn1 | head
Internals top:
- Первая строка — uptime, load average.
- Вторая — task counts.
- Третья — %CPU breakdown.
- Четвёртая-пятая — mem и swap.
- Остальное — процессы.
В top интерактивно нажмите:
1— показать CPU на каждое ядро отдельно.H— показывать потоки, а не процессы.c— полная командная строка.M— сортировка по памяти.P— сортировка по CPU.k— послать сигнал процессу.r— renice (изменить приоритет).
htop гораздо удобнее: цвета, поиск (F3), tree view (F5), kill (F9). Если есть возможность установить — ставьте.
sudo apt install htop # Debian/Ubuntu
sudo dnf install htop # Fedora
pgrep и pkill: поиск процессов по имени/атрибутам
pgrep ищет процессы и возвращает PID, pkill — то же, но сразу убивает.
# Найти процессы по имени:
pgrep nginx
# 1234
# 5678
# Точное имя (по умолчанию substring):
pgrep -x nginx
# Имя процесса + полная командная строка:
pgrep -fl nginx
# Пользователя:
pgrep -u username
# Внуки определённого процесса:
pgrep -P 1234 # дети PID 1234
# Самый новый/старый процесс этого имени:
pgrep -n nginx # newest
pgrep -o nginx # oldest
pkill идентичен по аргументам, но сразу шлёт сигнал (SIGTERM по умолчанию):
# Послать SIGTERM всем nginx:
pkill nginx
# SIGKILL (форсированно):
pkill -9 nginx
# По пользователю:
pkill -u username -9
# (опасно! Убивает все процессы пользователя)
Будьте аккуратны: pkill -9 -u username без проверки можно увидеть себя в ssh-сессии, как она обрывается :)
kill: отправка сигналов
kill — классическая команда. Несмотря на название, она не только убивает — она шлёт сигналы.
# Послать SIGTERM (по умолчанию):
kill 1234
# SIGKILL (нельзя поймать, форсированно):
kill -9 1234
# SIGHUP (часто используется для reload config):
kill -1 1234
# или
kill -HUP 1234
# Список всех сигналов:
kill -l
# 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL ...
Часто используемые сигналы
Сигналы и kill: как правильно убивать процессыГраceful shutdown: SIGTERM перед SIGKILL
Хороший паттерн при выключении сервиса:
# Послать SIGTERM, ждать 10 секунд:
kill 1234
sleep 10
# Проверить, жив ли:
if kill -0 1234 2>/dev/null; then
# Ещё жив -- послать SIGKILL
kill -9 1234
fi
kill -0 не шлёт сигнал, просто проверяет, существует ли процесс и есть ли права. Используется для проверки.
systemd делает это автоматически: при systemctl stop посылает SIGTERM, ждёт TimeoutStopSec (по умолчанию 90s), потом SIGKILL.
Сигналы в Python
import signal
import sys
import time
def handler(signum, frame):
print(f"Got signal {signum}, exiting...")
sys.exit(0)
# Перехватить SIGTERM и SIGHUP
signal.signal(signal.SIGTERM, handler)
signal.signal(signal.SIGHUP, handler)
print(f"PID: {os.getpid()}, waiting for signal...")
while True:
time.sleep(1)
Запустите, в другом терминале kill <PID> — увидите graceful exit. kill -9 <PID> — мгновенная смерть без handler (SIGKILL нельзя перехватить).
pstree: иерархия процессов
pstree показывает дерево процессов. Удобно понять, кто кого запустил.
# Всё дерево:
pstree
# С PID:
pstree -p
# Конкретного пользователя:
pstree -u username
# Поддерево конкретного PID:
pstree -p 1234
# Linkage между потоками:
pstree -T # без потоков
pstree -t # с потоками
Пример вывода:
systemd(1)
├── NetworkManager(820)
├── sshd(945)
│ └── sshd(2345)
│ └── bash(2348)
│ ├── htop(8901)
│ └── pstree(9001)
├── nginx(1234)
│ ├── nginx(1235)
│ ├── nginx(1236)
│ └── nginx(1237)
└── ...
Видно: systemd — PID 1. sshd запустил вашу bash-сессию (2348). bash запустил htop и pstree. nginx запустил воркеров.
Эта картина помогает понять «структуру» системы: где сервисы, какие у них воркеры, что запускает что.
Глубокая диагностика через /proc/[pid]
Когда стандартных тулзов не хватает — лезьте прямо в /proc/[pid]/. Это все данные о процессе из ядра.
Содержимое /proc/[pid]/ — что где
ls /proc/$$/ # вашего shell
Главные файлы:
- status — человекочитаемое состояние (Name, State, PID, PPID, Uid, VmRSS, …).
- stat — то же одной строкой (для ps, top).
- maps — виртуальная память.
- smaps — то же + детально по каждой VMA (резидент, swap, dirty).
- cmdline — argv процесса.
- environ — окружение.
- cwd -> symlink на текущую директорию.
- exe -> symlink на бинарь.
- fd/ — открытые файлы как symlinks.
- wchan — на каком syscall ждёт.
- stack — kernel stack trace (требует root).
- io — I/O статистика: сколько прочёл/записал.
- limits — ulimits процесса.
- task/ — подкаталог на каждый поток процесса.
Полезные одностроки
PID=1234 # подставьте свой
# Полная информация:
cat /proc/$PID/status
# Что процесс читает/пишет:
cat /proc/$PID/io
# rchar: 12345 -- сколько байт прочитал через read syscalls
# wchar: 5678 -- сколько записал через write
# syscr: 100 -- сколько read syscalls
# syscw: 50 -- сколько write syscalls
# read_bytes: 8192 -- реально с диска
# write_bytes: 4096 -- реально на диск
# Открытые файлы:
ls -la /proc/$PID/fd/
# Какие файлы и сокеты держит процесс:
ls -la /proc/$PID/fd/ | head
# lrwx------ 1 user user 64 May 18 14:00 0 -> /dev/null
# lrwx------ 1 user user 64 May 18 14:00 1 -> /var/log/app.log
# lrwx------ 1 user user 64 May 18 14:00 2 -> /var/log/app.log
# lrwx------ 1 user user 64 May 18 14:00 3 -> socket:[12345]
# lrwx------ 1 user user 64 May 18 14:00 4 -> /etc/myapp.conf
# Карта памяти:
cat /proc/$PID/maps | head
# Сколько памяти каждая VMA реально занимает (с резидентностью):
cat /proc/$PID/smaps | head -50
# Где процесс висит:
cat /proc/$PID/wchan
# Если запущен -- '0', если sleeps -- имя kernel-функции (например, ep_poll, futex_wait)
# Стек вызовов в ядре (требует root):
sudo cat /proc/$PID/stack | head -10
lsof — удобная обёртка над /proc
Сетевая диагностика: ping, dig, ss, nc, traceroutelsof (List Open Files) — удобная утилита для просмотра открытых файлов:
# Все открытые файлы конкретного процесса:
lsof -p 1234
# Все процессы, использующие файл:
lsof /var/log/syslog
# Все TCP сокеты в LISTEN состоянии:
lsof -iTCP -sTCP:LISTEN
# Кто слушает на порту 80:
lsof -i :80
# Что использует /tmp:
lsof +D /tmp
lsof показывает не только файлы, но и сокеты, pipes, devices. Очень мощный.
ulimit: лимиты процесса
Свой systemd-сервис: пишем .service unitУ каждого процесса есть лимиты:
- Максимум открытых fd (ulimit -n)
- Максимум памяти (ulimit -m, обычно unlimited)
- Максимум CPU time (ulimit -t)
- Максимум size of core dumps (ulimit -c)
- Максимум size of stack (ulimit -s)
- Максимум количество процессов на user (ulimit -u)
# Посмотреть лимиты текущего shell:
ulimit -a
# Открытые fd:
ulimit -n
# Обычно 1024
# Поднять для текущего shell (если разрешено):
ulimit -n 65536
# Лимиты конкретного процесса:
cat /proc/<PID>/limits
В production это критично для серверов. Nginx или PostgreSQL хотят открыть много fd (тысячи сокетов и файлов). Лимит 1024 — мало. Поднимают через systemd unit (LimitNOFILE=65536) или /etc/security/limits.conf.
Реальные сценарии
Сценарий 1: «Что-то ест память, не знаю что»
# Топ-10 по RSS:
ps -eo pid,user,rss,vsz,cmd --sort=-rss | head -11
# Если самый большой -- это Python скрипт:
PID=12345
cat /proc/$PID/status | grep -E '^Vm|^Threads'
# VmPeak: 4194304 kB -- максимум, что когда-либо было allocated
# VmSize: 3000000 kB -- сколько сейчас virtual
# VmRSS: 1500000 kB -- сколько физически (это реальная нагрузка на RAM)
# Threads: 16 -- столько threads
# Карта памяти:
cat /proc/$PID/smaps | grep -E '^(Size|Rss|Pss|Shared|Private)' | head -50
# Видно, какие отдельные mapping'и сколько занимают
Сценарий 2: «Процесс висит, что делает»
# State:
ps -o stat,wchan -p $PID
# D ext4_sync_file -- висит в fsync ext4
# или
# S futex_wait_queue -- ждёт synchronization
# или
# S inet_csk_accept -- ждёт TCP connection
# Активные syscalls:
sudo strace -p $PID 2>&1 | head -10
# Покажет, на каких syscall'ах висит
# Что в стеке (требует root):
sudo cat /proc/$PID/stack | head
Сценарий 3: «Не могу удалить файл, говорит busy»
# Файл /var/log/old.log не удаляется -- кто его держит:
lsof /var/log/old.log
# Видно процесс. Можно его убить, или попросить переоткрыть лог (kill -HUP).
Сценарий 4: «Слишком много open files, EMFILE»
# Лимит:
ulimit -n
# Реальное количество fd у процесса:
ls /proc/$PID/fd/ | wc -l
# Что за fd, может быть утечка (тысячи sockets):
ls -la /proc/$PID/fd/ | awk '{print $11}' | sort | uniq -c | sort -rn | head
Попробуй сам
# 1. Найти топ-5 процессов по памяти:
ps -eo pid,user,rss,vsz,cmd --sort=-rss | head -6
# 2. Посмотреть всё про себя (shell):
cat /proc/$$/status | head -20
ls -la /proc/$$/fd/
cat /proc/$$/limits
# 3. Trace процесс:
sleep 30 &
PID=$!
sudo strace -p $PID 2>&1 | head -5
# Покажет на каком syscall ждёт (nanosleep)
kill $PID
# 4. Sigtest -- послать сигнал, посмотреть как программа реагирует:
sleep 100 &
PID=$!
kill -STOP $PID
ps -o stat,pid -p $PID # T+
kill -CONT $PID
ps -o stat,pid -p $PID # S
kill $PID
# 5. Посмотреть, кто слушает на портах:
sudo lsof -iTCP -sTCP:LISTEN -P -n | head
# 6. Изменить приоритет (nice) тяжелого процесса:
nice -n 19 sha256sum /etc/* > /dev/null &
PID=$!
ps -o pid,ni,pri,cmd -p $PID
# Видно nice=19, низкий приоритет
kill $PID
# 7. Дерево процессов:
pstree -p $$ | head
# 8. Найти zombie:
ps -eo stat,pid,cmd | awk '$1 ~ /^Z/' | head
# Может быть пусто, если нет zombies