Основы процессов в Linux¶
Что такое процесс¶
Процесс — это экземпляр выполнения программы. Это изолированная единица, которой ядро операционной системы выделяет ресурсы и управляет её жизненным циклом.
Процесс — это живой объект в памяти, появляющийся при запуске программы. Программа — статичный ELF-файл на диске; процесс — её исполнение с собственными ресурсами. Одной программе может соответствовать сколько угодно параллельных процессов.
Каждый процесс обладает следующими атрибутами:
- адресное пространство — виртуальная память: сегменты кода, данных, стека и кучи;
- контекст выполнения — значения регистров процессора, счётчик команд, состояние памяти;
- привилегии — UID, GID, effective UID, capabilities;
- таблица файловых дескрипторов — набор открытых файлов, сокетов, пайпов;
- сигнальная маска — список ожидающих и заблокированных сигналов;
- текущая рабочая директория (CWD).
PCB (Process Control Block) — что хранит ядро о процессе
struct task_struct в Linux kernel
┌─────────────────────────────────────────────────────────┐
│ task_struct │
├──────────────────────────┬──────────────────────────────┤
│ Идентификация │ Состояние │
│ ┌────────────────────┐ │ ┌────────────────────────┐ │
│ │ pid (PID) │ │ │ state: R/S/D/T/Z │ │
│ │ tgid (thread grp) │ │ │ exit_code │ │
│ │ ppid (PPID) │ │ └────────────────────────┘ │
│ └────────────────────┘ │ │
├──────────────────────────┼──────────────────────────────┤
│ Адресное пространство │ Планировщик │
│ ┌────────────────────┐ │ ┌────────────────────────┐ │
│ │ mm_struct ──▶ │ │ │ prio / nice │ │
│ │ .text / .data │ │ │ sched_class │ │
│ │ .heap / .stack │ │ │ cpus_allowed │ │
│ │ mmap list │ │ └────────────────────────┘ │
│ └────────────────────┘ │ │
├──────────────────────────┼──────────────────────────────┤
│ Файловые дескрипторы │ Привилегии │
│ ┌────────────────────┐ │ ┌────────────────────────┐ │
│ │ files_struct ──▶ │ │ │ uid / gid │ │
│ │ fd[0] stdin │ │ │ euid / egid │ │
│ │ fd[1] stdout │ │ │ capabilities │ │
│ │ fd[2] stderr │ │ └────────────────────────┘ │
│ │ fd[3] ... │ │ │
│ └────────────────────┘ │ │
├──────────────────────────┼──────────────────────────────┤
│ Сигналы │ Прочее │
│ ┌────────────────────┐ │ ┌────────────────────────┐ │
│ │ pending signals │ │ │ CWD (fs_struct) │ │
│ │ blocked mask │ │ │ rlimits │ │
│ │ signal handlers │ │ │ cgroups │ │
│ └────────────────────┘ │ └────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
/proc/<pid>/status — удобный способ увидеть большинство этих полей
Идентификаторы процесса: PID и PPID¶
Каждый процесс в системе идентифицируется уникальным числом:
- PID (Process ID) — уникальный идентификатор процесса, выдаваемый ядром при его создании. Остаётся неизменным на протяжении всей жизни процесса.
- PPID (Parent Process ID) — PID родительского процесса, который создал данный процесс через
fork().
Все процессы в системе образуют дерево с корнем в init (PID = 1) или systemd.
Получить PID и PPID из программы:
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t mypid = getpid(); // мой PID
pid_t parentpid = getppid(); // PID родителя
printf("PID=%d, PPID=%d\n", mypid, parentpid);
return 0;
}
Из командной строки:
Дерево процессов¶
Поскольку каждый процесс знает своего родителя, все процессы системы образуют иерархическое дерево. Его можно
визуализировать командой pstree:
pstree # дерево всех процессов
pstree -p # с отображением PID
pstree -p -s <pid> # цепочка предков для конкретного процесса
pstree <user> # только процессы конкретного пользователя
Альтернативно, команда ps поддерживает режим отображения в виде дерева:
Мониторинг использования ресурсов¶
Команда ps позволяет получить снимок состояния процессов:
ps aux # все процессы с %CPU и %MEM
ps aux --sort=-%mem # отсортировано по памяти (убывание)
ps aux --sort=-%cpu # отсортировано по CPU (убывание)
ps -eo pid,user,vsz,rss,comm # кастомный формат
Два ключевых показателя использования памяти:
| Метрика | Описание |
|---|---|
| VSZ (Virtual Memory Size) | Размер всего виртуального адресного пространства процесса, включая незагруженные в RAM страницы |
| RSS (Resident Set Size) | Объём физической оперативной памяти, реально занятой процессом |
Для интерактивного мониторинга в реальном времени используется top или htop:
top # интерактивный монитор
top -p <pid> # только конкретный процесс
htop # более удобная версия top
Идентификаторы пользователя: UID, EUID и CWD¶
Каждый процесс имеет набор идентификаторов пользователя, влияющих на его права доступа:
- UID (Real User ID) — реальный ID пользователя, который запустил процесс. Обычно не меняется в течение жизни процесса.
- EUID (Effective User ID) — идентификатор, который ядро использует при проверке прав доступа к файлам и другим ресурсам. Именно EUID определяет, может ли процесс открыть файл, привязаться к порту или выполнить привилегированную операцию.
- CWD (Current Working Directory) — текущая рабочая директория процесса; используется при разрешении относительных путей.
В обычной ситуации UID == EUID, однако они могут расходиться при использовании SUID-битов, вызовах setuid() или при
управлении capabilities. Классический пример: программа /usr/bin/passwd запускается обычным пользователем (UID =
1000), но на её исполняемом файле установлен SUID-бит, поэтому её EUID равен 0 (root).
Получить идентификаторы из программы:
#include <unistd.h>
#include <stdio.h>
int main() {
printf("UID=%d, EUID=%d\n", getuid(), geteuid());
char cwd[256];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
printf("CWD=%s\n", cwd);
}
return 0;
}
Из командной строки:
Изменить идентификатор пользователя или директорию из программы:
#include <unistd.h>
// Изменить UID (обычно требует привилегий root)
if (setuid(1000) == -1) {
perror("setuid failed");
}
// Установить только EUID (для SUID-бинарей)
if (seteuid(0) == -1) {
perror("seteuid failed");
}
// Сменить текущую директорию
if (chdir("/tmp") == -1) {
perror("chdir failed");
}
Из командной строки:
Файловая система /proc¶
Каждый живой процесс представлен в псевдофайловой системе /proc в виде директории /proc/<pid>/. Это основной
интерфейс для интроспекции процессов без использования системных вызовов.
Ключевые файлы и директории:
| Путь | Содержимое |
|---|---|
/proc/<pid>/status |
Имя, PID, PPID, UID, GID, состояние, потребление памяти |
/proc/<pid>/cmdline |
Командная строка запуска (аргументы разделены нулевым байтом) |
/proc/<pid>/environ |
Переменные окружения процесса |
/proc/<pid>/maps |
Карта виртуальных регионов памяти (сегменты, библиотеки, стек, куча) |
/proc/<pid>/fd/ |
Символические ссылки на все открытые файловые дескрипторы |
/proc/<pid>/exe |
Символическая ссылка на исполняемый файл |
/proc/<pid>/cwd |
Символическая ссылка на текущую рабочую директорию |
/proc/<pid>/task/ |
Поддиректории для каждого потока (по TID) |
Примеры:
cat /proc/self/status # информация о текущем процессе
ls -la /proc/self/fd/ # открытые файловые дескрипторы
cat /proc/self/maps # карта памяти процесса
readlink /proc/self/exe # путь к текущему исполняемому файлу
Подробнее о карте памяти и виртуальных регионах см. в статье Виртуальная память.
Связанные темы¶
- Виртуальная память — адресное пространство процесса, сегменты кода/данных/стека/кучи
- fork и exec — как создаются дочерние процессы
- Состояния процессов, wait, sleep — жизненный цикл процесса
Источники¶
man 1 ps— документация по команде psman 1 pstree— документация по pstreeman 1 top— документация по topman 2 getpid— системные вызовы getpid, getppidman 2 getuid— getuid, geteuid, getgid, getegidman 2 setuid— setuid, seteuidman 2 chdir— изменение рабочей директорииman 5 proc— файловая система /proc