Что такое процесс и зачем тут ps
Процесс - это запущенная программа: код плюс выделенная ей память, открытые файлы, переменные окружения и так далее. У каждого процесса в Linux есть номер - PID (process ID). И есть PID родителя - PPID (parent PID), потому что в Linux процессы не возникают из воздуха: один процесс порождает другой системным вызовом fork (или clone). В самом верху этой пирамиды стоит init-процесс с PID 1 (на современных системах это systemd) - предок всех остальных. Важная деталь 2026: systemd как PID 1 является "субреапером", то есть автоматически усыновляет осиротевшие процессы и подбирает за ними - дальше это пригодится в разговоре про зомби.
Главный инструмент, чтобы увидеть linux процессы прямо сейчас, - это ps (process status). Он делает моментальный снимок: показывает, что происходит в момент запуска команды, и завершается. Этим он отличается от top/htop, которые обновляют картинку в реальном времени. Для разовой диагностики снимок ps часто удобнее: его можно скопировать, отгрепать, сохранить в файл, приложить к тикету. На современных дистрибутивах ps идёт из пакета procps-ng (версии 4.x), та же кодовая база у pgrep, pkill, pstree, pidof - это важно помнить, потому что флаги у них согласованы.
У ps исторически два набора флагов, и новичков это путает. Есть BSD-стиль (флаги без дефиса) и UNIX/POSIX-стиль (флаги с дефисом). Это не просто косметика - они дают разные колонки по умолчанию:
- ps aux - BSD-стиль. Показывает USER, PID, %CPU, %MEM, VSZ, RSS, TTY, STAT, START, TIME, COMMAND. Удобен, когда интересны CPU и память.
- ps -ef - UNIX-стиль. Показывает UID, PID, PPID, C, STIME, TTY, TIME, CMD. Удобен, когда нужен PPID (кто родитель).

Читаем вывод ps aux по колонкам
Теория без интерпретации бесполезна, поэтому смотрим на реальный вывод и разбираем каждое поле.
Код: Выделить всё
$ ps aux | head -4
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 167840 11200 ? Ss 09:01 0:03 /sbin/init
www 912 12.5 4.3 982340 351200 ? Sl 09:14 2:41 php-fpm: pool www
postgres 770 0.7 8.1 1450220 660400 ? Ss 09:12 0:55 postgres: main
- USER - от чьего имени работает процесс. Если веб-сервис крутится от root - это повод задуматься о безопасности.
- PID - номер процесса. Его подставляют в kill, strace, ну и вообще он главный идентификатор.
- %CPU - доля процессора. Может быть больше 100, если процесс многопоточный и грузит несколько ядер (100 = одно полное ядро). Учти: ps считает %CPU как среднее за всё время жизни процесса, а не "вот сейчас", поэтому для мгновенной картины CPU лучше top/htop, а ps - для снимка и сортировки.
- %MEM - доля физической памяти (RSS) от общей RAM.
- VSZ - виртуальный размер (сколько адресного пространства зарезервировано) в килобайтах. Часто пугающе большой, но это НЕ реально занятая RAM.
- RSS - resident set size, вот это уже реально занятая физическая память в килобайтах. Для оценки "кто съел память" смотри на RSS, а не на VSZ. Тонкость: RSS включает разделяемые библиотеки, поэтому сумма RSS всех процессов может быть больше реальной RAM. Для честной оценки уникальной памяти процесса есть поле PSS из /proc/PID/smaps_rollup (но это уже за пределами ps).
- TTY - терминал. Знак ? означает, что процесс не привязан к терминалу (демон).
- STAT - состояние. О нём ниже отдельно, это самое интересное.
- TIME - сколько процессорного времени процесс суммарно сжёг (не время с момента старта, а именно CPU-время).
Код: Выделить всё
# Топ-10 по потреблению CPU (знак минус = по убыванию)
ps -eo pid,ppid,user,%cpu,%mem,stat,comm --sort=-%cpu | head -n 11
# Топ-10 по памяти (по RSS)
ps -eo pid,user,rss,%mem,stat,comm --sort=-rss | head -n 11
Колонка STAT и состояние процесса в linux
Вот ради чего всё затевалось. Состояние процесса в linux - это первое, на что смотрит инженер при зависании. Первая буква в STAT - это и есть основное состояние:
- R - running или runnable. Процесс прямо сейчас выполняется на CPU или готов выполняться и стоит в очереди (runqueue). Много R при высокой нагрузке - это нагрузка на процессор.
- S - interruptible sleep, прерываемый сон. Процесс спит и ждёт события (сетевого пакета, ввода, таймера). Его можно разбудить сигналом. Подавляющее большинство процессов в системе именно в S - это норма, они просто ждут работу.
- D - uninterruptible sleep. Процесс спит так, что обычными сигналами его не трогают, потому что он ждёт завершения операции ядра, почти всегда дискового ввода-вывода. Один-два D на миг - нормально (так выглядит любое активное чтение/запись). Но если процессы надолго залипают в D - это красный флаг. Это тот самый d state linux, из-за которого load average улетает в небеса, хотя CPU при этом простаивает: машина не считает, а ждёт диск (или зависший NFS, или сбойный накопитель). Про убийство D-процессов есть важный нюанс 2026 - сразу ниже.
- Z - zombie, зомби. Процесс уже завершился, но его родитель ещё не забрал код возврата (не сделал wait). Зомби не потребляет CPU и память - от него остаётся только запись в таблице процессов. Опасен он не сам по себе, а как симптом: если зомби копятся пачками, значит родитель написан криво и не подбирает за детьми. Когда упрёшься в лимит PID (kernel.pid_max), система не сможет создавать новые процессы. Убить зомби нельзя (он и так мёртв) - лечится либо тем, что родитель наконец сделает wait, либо смертью самого родителя.
- T - stopped, остановлен сигналом job control (например, Ctrl+Z или kill -STOP). Процесс заморожен и ждёт SIGCONT.
- t - tracing stop, остановлен под отладчиком (strace, gdb). Полезно отличать от T: это не job control, а трассировка.
- I - idle, простаивающий поток ядра (увидишь у kworker и подобных). Состояние появилось в ядре 4.14, чтобы такие потоки не накручивали load average. На любом современном ядре 6.x это норма.
После основной буквы идут дополнительные флаги-модификаторы, их полезно понимать:
- s - процесс является лидером сессии.
- l - многопоточный (использует CLONE_THREAD).
- + - находится в foreground-группе процессов (на переднем плане в терминале).
- < - повышенный приоритет (отрицательный nice).
- N - пониженный приоритет (положительный nice).
- L - имеет страницы, залоченные в памяти (mlock).
Код: Выделить всё
$ ps aux | grep defunct
user 4123 0.0 0.0 0 0 ? Z 10:22 0:00 [worker] <defunct>
Куда смотреть дальше: wchan и диагностика D-state
Самый частый прикладной вопрос - "процессы залипли в D, что они ждут?". Не угадывай - спроси у ядра, в какой функции процесс заснул. Это показывает поле wchan (wait channel):
Код: Выделить всё
$ ps -eo pid,user,stat,wchan:24,comm --sort=-stat | head
PID USER STAT WCHAN COMMAND
5012 www D folio_wait_bit_common php-fpm
5013 www D nfs_wait_on_request php-fpm
Код: Выделить всё
sudo cat /proc/5012/stack
Код: Выделить всё
$ cat /proc/pressure/io
some avg10=42.13 avg60=38.40 avg300=20.05 total=...
full avg10=31.02 avg60=27.66 avg300=15.10 total=...
Дерево процессов: pstree, родитель и потомок
ps показывает плоский список, а связи родитель-потомок по нему читать неудобно. Для иерархии есть pstree - он рисует дерево, наглядно показывая, кто кого породил:
Код: Выделить всё
$ pstree -p
systemd(1)-+-sshd(820)---sshd(1502)---bash(1503)
|-nginx(900)-+-nginx(901)
| `-nginx(902)
`-php-fpm(912)-+-php-fpm(940)
`-php-fpm(941)
Чтобы увидеть потоки внутри процесса (а не только сами процессы), у ps есть флаг -L. Он добавляет колонки LWP (light weight process, идентификатор потока) и NLWP (число потоков):
Код: Выделить всё
ps -L -p 912 -o pid,lwp,nlwp,stat,%cpu,comm
И последнее из базиса - быстрый поиск процесса по имени без grep. Для этого есть pgrep (и его брат pkill для сигналов):
Код: Выделить всё
pgrep -a nginx # PID-ы и полные командные строки всех nginx
pgrep -u www php-fpm # только процессы пользователя www
pgrep -c php-fpm # просто посчитать количество
Типичные грабли и заблуждения
- VSZ - это не съеденная память. Новички пугаются гигантских чисел в VSZ. Реально занятую RAM показывает RSS, а честную уникальную - PSS.
- Высокий load average при простое CPU. Классика: load average 30, а %CPU почти нулевой. Значит, процессы стоят в D-state и ждут диск или сеть. Лечится не докидыванием ядер, а разбором, куда упирается ввод-вывод - подтверди через /proc/pressure/io, wchan, дальше iostat/iotop (или eBPF-инструмент biolatency).
- Попытка убить зомби. kill по зомби не сработает - он уже мёртв. Смотри на его родителя (PPID) в ps -ef, проблема в нём.
- "kill -9 никогда не берёт D-процесс". Устаревшее правило. На современном ядре часть D-сна - killable и реагирует на SIGKILL (например NFS). Не убивается только классический непрерываемый сон.
- ps -aux против ps aux. Разные стили разбора флагов. Привыкай к ps aux без дефиса.
- Idle-потоки больше не пугают. Состояние I у kworker - это нормально и не накручивает load. Не путай с D.
- Выполни ps aux | head и найди свои процессы по столбцу USER. Посмотри на STAT - большинство ли в S?
- Выведи топ по памяти: ps -eo pid,user,rss,stat,comm --sort=-rss | head. Кто занял больше всего RSS? Сравни с VSZ того же процесса.
- Запусти sleep 600 на переднем плане, нажми Ctrl+Z и найди его в ps - увидишь состояние T. Верни в работу через fg или bg.
- Посмотри, что ждут процессы: ps -eo pid,stat,wchan:24,comm | grep -E " D | S " | head.
- Подсмотри давление ввода-вывода: cat /proc/pressure/io (нужен cgroup v2, по умолчанию на современных дистрибутивах).
- Нарисуй дерево: pstree -p и найди в нём свой bash и его родителя. Затем pstree -s $$ - цепочка предков твоей оболочки.
- Найди процесс по имени: pgrep -a sshd.
- Чем отличается вывод ps aux от ps -ef и когда какой удобнее?
- Что означает состояние D в колонке STAT, и правда ли, что такой процесс невозможно убить даже kill -9? Поясни, от чего это зависит на современном ядре.
- Что такое зомби-процесс, чем он опасен и как от него избавиться?
- Какую колонку смотреть, чтобы оценить реально занятую процессом память - VSZ или RSS, и почему?
- Куда смотреть, чтобы понять, что именно ждёт залипший в D процесс?
ps - твой первый инструмент при разборе зависаний: ps aux для CPU и памяти, ps -ef для родителей, ps -eo для своих колонок с сортировкой. Связи процессов смотри через pstree, потоки - через ps -L, ищи по имени через pgrep. Главное - научись читать колонку STAT: R значит работает или готов, S - нормальный сон, D - залип на вводе-выводе (тревога, если надолго), Z - зомби (симптом кривого родителя), T - остановлен. Если упёрся в D - не гадай, смотри wchan, /proc/PID/stack и /proc/pressure/io. Состояние процесса - это самый быстрый способ понять, машина считает, ждёт диск или просто простаивает.