Открыть сервис

Виртуальное адресное пространство

Виртуальное адресное пространство — это набор адресов памяти, который операционная система предоставляет каждому процессу (запущенной программе) в многозадачной вычислительной системе. В отличие от физического адресного пространства, которое соответствует реальным ячейкам оперативной памяти (RAM), виртуальное адресное пространство является абстрактным, изолированным и, как правило, непрерывным. Оно служит промежуточным звеном между адресами, используемыми программой (виртуальными адресами), и физическими адресами памяти. Механизм трансляции виртуальных адресов в физические реализуется блоком управления памятью (MMU) центрального процессора при поддержке операционной системы.

История возникновения

Необходимость в виртуализации памяти возникла с появлением первых многозадачных операционных систем в 1960-х годах. Ранние компьютеры работали с физическими адресами напрямую, что приводило к нескольким проблемам: программа могла случайно или намеренно повредить память другой программы, а фрагментация памяти затрудняла выделение больших непрерывных блоков.

Концепция виртуальной памяти была впервые реализована в 1961 году в мэйнфрейме Atlas (Великобритания) в рамках проекта Манчестерского университета. Система использовала страничную организацию памяти и аппаратное устройство для трансляции адресов. В 1970-х годах идея была развита в операционной системе Multics, а затем популяризирована в Unix. Массовое внедрение виртуального адресного пространства в персональных компьютерах началось с процессора Intel 80386 (1985 год), который поддерживал страничную адресацию и защищённый режим.

Принцип работы

Виртуальное адресное пространство функционирует на основе двух ключевых механизмов: страничной адресации (paging) и трансляции адресов.

Страничная организация

Физическая память делится на блоки фиксированного размера, называемые страницами (обычно 4 КБ в x86-архитектуре, возможны большие размеры — 2 МБ, 1 ГБ). Виртуальное адресное пространство процесса также разбивается на виртуальные страницы того же размера. Операционная система ведёт для каждого процесса таблицу страниц (page table), которая отображает виртуальные номера страниц на физические номера кадров (page frames) в RAM или указывает, что страница выгружена на диск (в файл подкачки или раздел своп).

Трансляция адресов

Когда процесс обращается к памяти по виртуальному адресу, процессор (MMU) выполняет следующие шаги:

  1. Разбивает виртуальный адрес на номер виртуальной страницы (VPN) и смещение внутри страницы (offset).
  2. Ищет запись для данного VPN в таблице страниц. Для ускорения используется кэш — буфер ассоциативной трансляции (TLB, Translation Lookaside Buffer), хранящий недавно использованные отображения.
  3. Если запись есть в TLB (попадание), MMU сразу получает физический номер кадра (PFN) и комбинирует его со смещением, формируя физический адрес.
  4. Если записи в TLB нет (промах), MMU обращается к таблице страниц в оперативной памяти. Если страница присутствует в RAM (бит присутствия установлен), отображение загружается в TLB, и доступ выполняется.
  5. Если страница отсутствует в RAM (страничный сбой, page fault), операционная система прерывает выполнение процесса, загружает требуемую страницу с диска в свободный кадр памяти, обновляет таблицу страниц и возобновляет выполнение инструкции, вызвавшей сбой.

Ключевые свойства и преимущества

Виртуальное адресное пространство обеспечивает несколько фундаментальных возможностей, отсутствующих при работе с физической памятью напрямую.

Изоляция процессов

Каждый процесс получает собственное, полностью изолированное виртуальное адресное пространство. Процесс A не может обратиться к памяти процесса B, так как его виртуальные адреса не отображаются на физические страницы, принадлежащие другому процессу. Это предотвращает случайное или злонамеренное повреждение данных соседних приложений и повышает стабильность системы.

Абстракция памяти

Программист и компилятор могут считать, что программа работает в непрерывном, однородном адресном пространстве, начиная, как правило, с адреса 0 (или другого фиксированного значения). Это упрощает компоновку кода и данных, так как не требуется учитывать фактическое расположение физической памяти или наличие свободных областей.

Перекрытие адресных пространств

Одна и та же физическая страница памяти может быть отображена в виртуальные адресные пространства нескольких процессов одновременно. Это используется для:

  • Разделяемой памяти (shared memory) — механизма межпроцессного взаимодействия (IPC).
  • Разделяемых библиотек (shared libraries, DLL) — код библиотеки загружается в физическую память один раз, но отображается в адресные пространства всех использующих её процессов, экономя RAM.
  • Отображения файлов в память (memory-mapped files).

Защита памяти

Каждая запись в таблице страниц содержит биты прав доступа (чтение, запись, исполнение). Операционная система может запретить процессу выполнение кода из области данных (NX-бит, DEP — Data Execution Prevention) или запись в область кода. Попытка нарушения прав приводит к генерации исключения (например, segmentation fault в Unix-подобных системах).

Расширение доступной памяти (свопинг)

Виртуальное адресное пространство может быть значительно больше, чем объём физической оперативной памяти. Неиспользуемые в данный момент страницы выгружаются на диск (в файл подкачки). Это позволяет запускать программы, совокупный размер которых превышает доступную RAM, ценой снижения производительности при обращении к выгруженным страницам.

Размер и структура

Размер виртуального адресного пространства определяется разрядностью архитектуры процессора и операционной системы.

  • 32-битные системы: максимальный размер виртуального адресного пространства составляет 2³² байт = 4 гигабайта (ГБ). В классической реализации Windows (до Windows 8) это пространство делилось пополам: 2 ГБ для процесса (пользовательский режим) и 2 ГБ для ядра (режим ядра). В Linux по умолчанию разделение было 3 ГБ / 1 ГБ.
  • 64-битные системы: теоретический предел — 2⁶⁴ байт (16 эксабайт). На практике современные процессоры (например, x86-64) используют только 48 или 57 бит для адресации, что даёт 256 тебибайт (TiB) или 128 петабайт (PiB) соответственно. Операционные системы, такие как Windows и Linux, обычно ограничивают пользовательское пространство до 128 TiB, а остальное резервируют для ядра.

Структура типичного виртуального адресного пространства процесса включает следующие сегменты (снизу вверх по адресам):

  • Текст (код): исполняемые инструкции программы, обычно доступные только для чтения и исполнения.
  • Данные: глобальные и статические переменные (инициализированные и неинициализированные — BSS).
  • Куча (heap): область для динамического выделения памяти (malloc, new). Растёт в сторону старших адресов.
  • Стек (stack): область для локальных переменных, параметров функций и адресов возврата. Растёт в сторону младших адресов.
  • Разделяемые библиотеки: отображённые файлы .so (Linux) или .dll (Windows).
  • Отображённые файлы: области, соответствующие файлам на диске (memory-mapped files).

Виртуальное адресное пространство ядра

Операционная система также использует собственное виртуальное адресное пространство для кода ядра, драйверов устройств и системных структур данных (таблиц страниц, буферов ввода-вывода). В зависимости от архитектуры, это пространство может быть отдельным (в 64-битных системах) или разделять адресное пространство с процессами (в 32-битных системах, где часть адресов зарезервирована для ядра). Доступ к памяти ядра из пользовательского режима аппаратно запрещён.

Ограничения и недостатки

  • Накладные расходы на трансляцию: каждое обращение к памяти требует выполнения нескольких операций MMU и обращения к таблице страниц, что увеличивает задержки. TLB частично компенсирует это, но промахи TLB могут быть дорогими.
  • Потребление памяти на таблицы страниц: для каждого процесса операционная система хранит многоуровневые таблицы страниц, которые могут занимать значительный объём физической памяти, особенно при большом количестве запущенных процессов.
  • Сложность реализации: управление виртуальной памятью требует сложного кода в ядре ОС, включая обработку страничных сбоев, планирование выгрузки страниц (алгоритмы замещения, например, LRU) и синхронизацию.
  • Проблемы производительности при свопинге: обращение к диску (даже SSD) в сотни тысяч раз медленнее, чем к RAM. Интенсивный свопинг (thrashing) может привести к катастрофическому падению производительности системы.

Применение в современных системах

Виртуальное адресное пространство является обязательным компонентом всех современных многозадачных операционных систем:

  • Windows (семейства NT): использует страничную организацию с размером страницы 4 КБ, поддерживает большие страницы (Large Pages) для приложений с высокими требованиями к производительности (базы данных, виртуальные машины).
  • Linux: полностью основан на виртуальной памяти, поддерживает множество алгоритмов управления памятью (включая OOM Killer для аварийного завершения процессов при нехватке памяти).
  • macOS (XNU): гибридное ядро, использующее виртуальную память на основе Mach и BSD.
  • Android и iOS: мобильные версии Linux и XNU соответственно, с дополнительной оптимизацией для ограниченных ресурсов (например, zRAM — сжатие страниц в RAM).

Виртуальное адресное пространство также лежит в основе технологий виртуализации (гипервизоры, контейнеры) и песочниц (sandboxing), где изоляция на уровне адресов является критической для безопасности.

Источники

  1. Таненбаум Э., Бос Х. «Современные операционные системы» (4-е издание, 2015).
  2. Intel Corporation. «Intel 64 and IA-32 Architectures Software Developer's Manual», Volume 3A: System Programming Guide (2023).
  3. Love R. «Linux Kernel Development» (3rd edition, 2010).
  4. Silberschatz A., Galvin P. B., Gagne G. «Operating System Concepts» (10th edition, 2018).
  5. Документация Microsoft: «Virtual Address Space» (Windows Driver Kit).

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →