Как устроена операционная система: ядро, процессы, память и файлы

Операционная система — это слой между железом и приложениями: она управляет процессором, памятью, дисками и сетью, даёт программам единый интерфейс и изолирует их друг от друга. Понимание того, как устроена операционная система, помогает разбираться в многозадачности, отладке, производительности и в том, почему одни программы «летают», а другие упираются в диск или CPU. В статье — архитектура ОС по слоям, ядро и системные вызовы, процессы и потоки, управление памятью, файловая система, виды ОС и примеры «что происходит под капотом», когда вы запускаете программу или открываете файл. Тем, кто настраивает серверы и автоматизацию, пригодятся DevOps-практики и работа с Shell и командной строкой.
Содержание
- Как устроена операционная система: общая картина
- Слои ОС: от железа до приложений
- Ядро: что внутри и зачем оно нужно
- Процессы и потоки: как ОС распределяет процессор
- Управление памятью: виртуальная память и страницы
- Файловая система: как хранятся файлы на диске
- Драйверы и аппаратная абстракция
- Системные вызовы: как приложение общается с ядром
- Пример: что происходит при запуске программы
- Пример: что происходит при открытии файла
- Виды операционных систем: монолит, микроядро, гибриды
- Частые вопросы
- Читайте также
- Выводы и что почитать дальше
Как устроена операционная система: общая картина
Операционная система (ОС) решает несколько задач сразу: даёт программам доступ к железу (процессор, оперативная память, диски, сеть), распределяет ресурсы между ними, защищает их друг от друга и от сбоев. Пользователь и приложения работают в пользовательском режиме (user space); код ОС, который напрямую общается с железом и принимает решения, работает в режиме ядра (kernel space). Переход между режимами происходит через системные вызовы (syscalls): приложение просит ядро выполнить действие (открыть файл, выделить память, создать процесс), процессор переключается в режим ядра, выполняется код ОС, результат возвращается в приложение.
Рис. 1 — Устройство ОС: приложения → системные вызовы → ядро → железо
Ниже разберём по шагам: что входит в ядро, как ОС управляет процессами и памятью, как устроена файловая система и как приложение вызывает код ядра. Тем, кто хочет копнуть ещё глубже в «железо», пригодятся статьи про устройство процессора и виды памяти ПК.
Зачем программисту понимать устройство ОС
Понимание того, как устроена операционная система, помогает не только на собеседованиях, но и в повседневной работе: отладка (почему процесс падает, что значит «out of memory»), профилирование (где время уходит — в CPU, в ожидании I/O, в подкачке), выбор конфигурации сервера и контейнеров. Когда приложение тормозит, знание иерархии памяти (кэш → ОЗУ → диск) и роли процессора подсказывает, куда смотреть первым делом. Тем, кто разворачивает приложения и настраивает окружение, полезны Shell и DevOps: автоматизация сборки, деплоя и мониторинга напрямую опирается на то, как ОС управляет процессами, файлами и сетью.
Слои ОС: от железа до приложений
Устройство операционной системы удобно представлять слоями.
Приложение не обращается к диску «напрямую»: оно вызывает, например, open("/home/user/file.txt"). Библиотека C передаёт вызов в ядро; ядро проверяет права, находит файл на диске (через драйвер и файловую систему), выделяет дескриптор и возвращает его в приложение. Так устройство операционной системы обеспечивает единый интерфейс для разного железа и защиту.
Ядро: что внутри и зачем оно нужно
Ядро (kernel) — центральная часть ОС. Оно выполняется в привилегированном режиме процессора (kernel mode) и может делать всё: обращаться к любому участку памяти, к портам ввода-вывода, отключать прерывания. Код приложений в user mode таких прав не имеет: попытка прямого доступа к «чужим» адресам или к железу приводит к исключению, которое обрабатывает ядро (часто — завершение процесса).
В ядре обычно живут:
- Планировщик (scheduler) — решает, какому процессу дать квант времени CPU (подробнее про роль CPU в системе — в статье «Процессор: устройство и принципы работы»).
- Подсистема управления памятью — распределяет ОЗУ, ведёт виртуальные адресные пространства, подкачку (swap); как устроена память компьютера и иерархия кэш–ОЗУ–диск — в отдельном материале.
- Файловые системы и VFS — абстракция «файл/каталог» поверх разных форматов дисков (ext4, NTFS и т.д.).
- Сетевой стек — протоколы (TCP/IP), сокеты, драйверы сетевых карт.
- Драйверы устройств — код, знающий, как общаться с конкретным железом (диск, USB, видеокарта).
Рис. 2 — Основные подсистемы ядра
Процессы и потоки: как ОС распределяет процессор
Процесс — это запущенная программа вместе с выделенным ей адресным пространством (памятью), открытыми файлами и учётной записью (кто владелец, какие права). Поток (thread) — поток выполнения внутри процесса; у потоков одного процесса общая память и файлы, но свой стек и свой контекст процессора (регистры, счётчик команд). ОС переключает CPU между потоками: даёт одному квант времени (например, несколько миллисекунд), по таймеру или при блокировке (ожидание I/O) переключается на другой — так создаётся иллюзия одновременной работы многих программ.
Жизненный цикл процесса (упрощённо): создан → готов к выполнению (ждёт CPU) → выполняется → при ожидании I/O или семафора переходит в ожидание → снова готов → снова выполняется → завершён.
Рис. 3 — Переходы между состояниями процесса
Пример. В Linux процесс создаётся системным вызовом fork() (копия текущего процесса) и часто сразу exec() (загрузка новой программы в память этого процесса). Оболочка, в которой вы вводите команды, — это Shell: она как раз вызывает fork() и exec(), когда вы запускаете программу. Планировщик держит очереди готовых процессов и по таймеру или при освобождении CPU переключает контекст на следующий поток.
Управление памятью: виртуальная память и страницы
Каждому процессу ядро выделяет виртуальное адресное пространство: процесс «видит» свои адреса (например, от 0 до 2^48 на 64-битной системе), но не видит память других процессов и не знает, по каким физическим адресам ОЗУ реально лежат его данные. За перевод виртуальных адр��сов в физические отвечает MMU (Memory Management Unit) процессора и структуры данных ядра: таблицы страниц (page tables). Память разбита на страницы (типичный размер 4 КБ); каждая виртуальная страница может быть привязана к физическому кадру в ОЗУ, помечена «нет в памяти» (тогда при обращении возникает page fault и ядро подкачивает страницу с диска) или ещё не выделена.
Так устройство операционной системы в части памяти даёт изоляцию (процесс A не может прочитать память процесса B), экономию ОЗУ (редко используемые страницы можно выгружать в swap) и возможность использовать больше виртуальной памяти, чем физически установлено RAM (за счёт подкачки). Как устроена память компьютера в целом — от кэша до диска и swap — разобрано в отдельной статье.
Рис. 4 — Виртуальные страницы отображаются на кадры ОЗУ (или swap)
Связь с тем, как устроена память компьютера (в том числе ОЗУ и кэш): данные процесса лежат в ОЗУ (и частично в swap); при обращении процессор подставляет их в кэш. ОС лишь распределяет ОЗУ и дисковый swap; скорость доступа по-прежнему определяется иерархией кэш → ОЗУ → диск.
Файловая система: как хранятся файлы на диске
Файловая система — способ хранить на диске именованные файлы и каталоги и быстро находить данные по пути. На диске есть метаданные (какие блоки заняты, где начало файла, права, владелец) и данные (содержимое файлов). В Unix-подобных ОС у каждого файла есть inode (index node): структура с типом файла, правами, временем изменения и указателями на блоки данных на диске. Имена файлов хранятся в каталогах: каталог — это по сути список «имя → inode». Поэтому одно и то же содержимое может быть доступно под разными именами (жёсткие ссылки — один inode, несколько записей в каталогах).
Рис. 5 — Каталог → inode → блоки данных
Пример. Открытие /home/user/file.txt: ядро по корню и по цепочке каталогов находит запись file.txt → inode 200; читает inode 200, получает номера блоков 501, 502; драйвер диска читает эти блоки в память; приложение получает дескриптор файла и может делать read()/write().
Драйверы и аппаратная абстракция
Ядро не знает деталей каждой модели диска или сетевой карты. Драйвер — модуль кода, который «переводит» общие запросы ядра (прочитать блок 501, отправить пакет в сеть) в команды конкретного устройства. Драйверы работают в режиме ядра; часть может быть встроена в ядро (монолит), часть подгружаться модулями (например, в Linux — kernel modules). Так операционная система даёт единый интерфейс (блочное устройство, символьное, сетевой интерфейс), а производители железа поставляют драйверы под популярные ОС. Как устроены процессор и память на уровне железа — в статьях по основам «железа».
Системные вызовы: как приложение общается с ядром
Приложение не может само переключить процессор в kernel mode. Оно вызывает функцию из библиотеки (например, open() из libc); внутри эта функция кладёт номер системного вызова и аргументы в регистры (или стек) и выполняет инструкцию перехода в ядро (на x86 — syscall или int 0x80). Процессор переключается в привилегированный режим, управление попадает в обработчик системных вызовов ядра; ядро по номеру вызывает нужный код (например, открытие файла), выполняет его и записывает результат в место, откуда user space прочитает возвращаемое значение. Затем процессор возвращается в user mode, и выполнение приложения продолжается.
Рис. 6 — Цепочка: приложение → syscall → ядро → возврат
Типичные группы системных вызовов: управление процессами (fork, exec, wait), память (brk, mmap), файлы (open, read, write, close), сокеты (socket, bind, connect, send, recv).
Пример: что происходит при запуске программы
Рис. 8 — shell → fork → exec → ядро загружает программу в память
- Пользователь вводит команду в оболочке (Shell) или кликает по ярлыку.
- Оболочка вызывает
fork()— создаётся копия процесса shell. - В дочернем процессе вызывается
exec("/usr/bin/программа", argv)— ядро загружает исполняемый файл: читает заголовок (ELF и т.п.), выделяет виртуальное адресное пространство, загружает сегменты кода и данных в память (или отображает их через mmap), подгружает динамические библиотеки, устанавливает точку входа и передаёт управление в user space. - Планировщик ставит новый процесс в очередь; когда даёт ему квант CPU, процесс начинает выполняться с точки входа (например,
main()).
Так как устроена операционная система видно на примере: один процесс (shell) через системные вызовы просит ядро создать другой процесс и загрузить в него новую программу; всё общение с диском и памятью идёт через ядро.
Пример: что происходит при открытии файла
Рис. 9 — open() → VFS → inode → fd; затем read() по fd
- Приложение вызывает
open("/path/to/file", O_RDONLY). - libc формирует системный вызов (например,
openatв Linux) с путём и флагами. - Управление переходит в ядро. Подсистема VFS (Virtual File System) разбирает путь: от корня или текущего каталога переходит по компонентам (path lookup), для каждой части находит inode каталога, читает каталог, находит следующий inode. Права проверяются на каждом шаге.
- Когда найден inode файла, ядро создаёт дескриптор открытого файла (file description): структуру с позицией чтения/записи, флагами, ссылкой на inode. В таблицу открытых файлов процесса добавляется запись; возвращаемый пользователю номер — это индекс в этой таблице (file descriptor, fd).
- При последующих
read(fd, buf, size)ядро по fd находит file description и inode, вычисляет блоки диска для текущей позиции, обращается к драйверу диска, копирует данные в буфер пользователя и обновляет позицию.
Оба примера показывают, что приложение не трогает диск и не управляет памятью напрямую — всё делается кодом ядра по запросу через системные вызовы.
Виды операционных систем: монолит, микроядро, гибриды
Монолитное ядро — большая часть ОС (планировщик, ФС, драйверы, сеть) работает в одном адресном пространстве в режиме ядра. Примеры: классический Linux, многие ядра BSD. Плюсы: быстрый вызов между подсистемами, меньше переключений контекста. Минусы: сбой в драйвере может положить всё ядро; код большой и сложный.
Микроядро — в режиме ядра только минимальный код: планирование потоков, передача сообщений, минимальная работа с памятью. Файловые системы, драйверы, сетевой стек работают в отдельных процессах в user space; общение с ядром и между сервисами — через сообщения. Примеры: QNX, Minix, часть разработок в академии. Плюсы: изоляция, отказ одного сервиса не роняет остальное. Минусы: больше переключений и копирований данных, сложнее достичь высокой производительности.
Гибридные — практический компромисс: часть драйверов и кода в ядре (как в монолите), часть вынесена в user space или в отдельные подсистемы. Так часто устроены современные Windows и отчасти macOS.
Рис. 7 — Монолитное ядро vs микроядро
Частые вопросы
Чем процесс отличается от потока? Процесс — это программа с собственным адресным пространством и ресурсами (файлы, сокеты). Поток — поток выполнения внутри процесса; у потоков одного процесса общая память, но свои стеки и контекст CPU. ОС планирует потоки (или процессы с одним потоком), переключая CPU между ними.
Что такое виртуальная память? Это способ представить память процесса: ему доступен диапазон виртуальных адресов; ядро и MMU переводят их в физические адреса ОЗУ (или подкачивают страницы с диска). Так процессы изолированы, и можно использовать больше виртуальной памяти, чем есть физической RAM (за счёт swap).
Зачем нужны системные вызовы? Приложение работает в непривилегированном режиме и не может само обращаться к диску или к памяти других процессов. Системный вызов — единственный «официальный» способ попросить ядро выполнить такое действие; процессор переключается в kernel mode, выполняется код ОС, результат возвращается приложению.
Какие бывают виды операционных систем по типу ядра? Монолитное ядро (почти вся ОС в ядре), микроядро (минимум в ядре, остальное — сервисы в user space), гибридные (комбинация подходов). По назначению: серверные, десктопные, встроенные, реального времени (RTOS).
Как ОС связана с железом? ОС распределяет время процессора между процессами, выделяет оперативную память и подкачку, обращается к дискам и сети через драйверы. Без ОС приложения не могли бы единообразно работать с разным железом; подробнее про роль памяти и CPU в системе — в статьях по памяти компьютера и устройству процессора.
Читайте также
- Память компьютера: виды и классификация — ОЗУ, кэш, swap и иерархия памяти.
- Процессор: устройство и принципы работы — CPU, ядра, кэш, связь с памятью.
- Shell: что это такое и зачем он нужен — как оболочка окружает ядро ОС и даёт доступ к системе.
- Что такое DevOps: простыми словами — автоматизация и эксплуатация рядом с разработкой.
Выводы и что почитать дальше
- Операционная система — слой между железом и приложениями: управляет CPU, памятью, дисками и сетью, даёт единый интерфейс и изоляцию. Как устроена операционная система: пользовательское пространство (приложения) и ядро (kernel space), переход через системные вызовы.
- В ядре живут планировщик, управление памятью (виртуальная память, страницы, swap), файловые системы и VFS, сетевой стек, драйверы устройств.
- Процессы и потоки — единицы планирования; ОС переключает CPU между ними, создавая многозадачность. Виртуальная память даёт каждому процессу своё адресное пространство и отображает страницы на ОЗУ или swap.
- Файловая система хранит метаданные (inode) и данные в блоках; каталоги связывают имена с inode. Системные вызовы — единственный способ приложения запросить действие ядра (открыть файл, выделить память, создать процесс).
- Виды операционных систем по архитектуре ядра: монолит (Linux), микроядро (QNX, Minix), гибриды (Windows, macOS).
Связь с другими темами. Устройство ОС стоит на стыке «железа» и программ: процессор выполняет команды и обменивается с памятью, ОС управляет ими и даёт приложениям интерфейс. Для работы с системой из командной строки пригодятся Shell; для автоматизации деплоя и инфраструктуры — DevOps.
Чтобы углубиться: книга «Operating Systems: Three Easy Pieces» (OSTEP), документация по системным вызовам Linux (man 2 syscalls), статьи по памяти компьютера и устройству процессора на Хекслете. Для работы с серверами и автоматизацией полезны Shell и DevOps-подход.
Категории