[Перевод] Управление памятью в Linux

Введение

Управление памятью (memory management) является важной подсистемой операционной системы Linux, которая обеспечивает эффективное использование ресурсов физической и виртуальной памяти. В Linux управление памятью в основном подразумевает обработку запросов к памяти от процессов, выделение и освобождение блоков памяти, а также обеспечение ее эффективного использования.

Ключевые понятия управления памятью в Linux:

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

  • Система страница (Paging)
    Физическая и виртуальная память разделены на блоки фиксированного размера, которые называются страницами. Система страниц позволяет эффективно управлять памятью и активирует механизм обмена данными между ОЗУ и диском (swap)

  • Выделение памяти (Memory Allocation)
    При выполнении команд процессам требуется память. За выделение процессам подходящих блоков памяти отвечает соответствующий диспетчер. Память выделяется из свободной физической памяти. При необходимости физическая память освобождается сбросом неактивных страниц на диск

  • Пространство ядра и пользовательское пространство (Kernel Space and User Space)
    Память в Linux подразделяется на пространство ядра и пользовательское пространство. Пространство ядра зарезервировано для исполнения кода ядра, расширений ядра и большинства драйверов устройств. Пользовательское пространство — это область памяти, с которой работают все пользовательские приложения

  • Кеширование (Caching)
    Linux использует несколько механизмов кеширования для улучшения производительности системы. Так, например, кеш страниц (page cache) используется для кеширования файлов, читаемых с диска, а кеш буфера (buffer cache) используется для управления операциями записи на диск

  • Чрезмерное выделение памяти (Memory Overcommit)
    Linux позволяет выделить процессам больше памяти, чем реально доступно. Эта концепция известна как memory overcommit. Она позволяет большему количество процессов выполняться одновременно при условии, что процессы не используют всю выделенную им память

Как работает виртуальная память

  • Сегментация памяти (Memory Segmentation)
    Когда приложение запускается, ему выделяется диапазон адресов виртуальной памяти. Эта память разделена на блоки (chunks), называемые страницами. Например, если наше приложение запускается и ему выделен диапазон адресов от 0x0000 до 0xFFFF, а размер страницы равен 0x1000 (значение по умолчанию — 4096 байт), то приложение получает 16 страниц (0x0000–0x0FFF, 0x1000–0x1FFF, …, 0xF000–0xFFFF)

  • Таблица страниц (Page Tables)
    Операционная система сохраняет для каждого процесса структуру данных, которая называется таблицей страниц. Таблица страниц сопоставляет адреса страниц виртуальной памяти с адресами страниц физической памяти. Например, первая страница нашего приложения 0x0000–0x0FFF может быть сопоставлена со физической страницей 0x2000–0x2FFF, вторая страница 0x1000–0x1FFF сопоставлена с физической страницей 0x5000–0x5FFF и так далее

  • Доступ к памяти (Memory Access)
    Когда приложение выполняет запрос на чтение или запись к памяти, ЦПУ использует таблицу страниц для трансляции адреса виртуальной памяти в адрес физической. Например, если наше приложение хочет прочитать адрес виртуальной памяти 0x1500, то происходит запрос ко второй странице виртуальной памяти, которая сопоставляется с физической страницей 0x5000–0x5FFF. Таким образом, ЦПУ нужно прочитать реальный адрес физической памяти 0x5500

  • Подкачка и запрос страниц (Swapping and Demand Paging)
    Если вся физическая память использована, а приложению требуется загрузить новую страницу в нее, то ОС может выбрать страницу физической памяти для сброса-«подкачки» (swap out) на диск. В таблицу страниц вносится пометка, что данная страница отсутствует в физической памяти. Если позднее приложение попытается получить доступ к адресу выгруженной на диск страницы, то это приведет к ошибке, и операционная система загрузит-«подкачает» (swap in) страницу с диска в физическую память (возможно сбросив при этом на диск другую страницу), после чего приложение сможет получить к ней доступ. Механизм загрузки страниц в физическую память при обращении к ним называется demand paging и позволяет общему объему виртуальной памяти для всех процессов превышать объем фактически доступной физической памяти

     Virtual Memory               Page Table                 Physical Memory
   ┌───────────────┐          ┌────────────────┐            ┌────────────────┐
   │ Page 1        │          │ Page 1         │            │ Page 4         │
   │ 0x0000-0x0FFF ├───────►  │  0x2000-0x2FFF ├─────────►  │ 0x2000-0x2FFF  │
   ├───────────────┤          ├────────────────┤            ├────────────────┤
   │ Page 2        │          │ Page 2         │            │ Page 1         │
   │ 0x1000-0x1FFF ├───────►  │ 0x5000-0x5FFF  ├─────────►  │ 0x5000-0x5FFF  │
   ├───────────────┤          ├────────────────┤            ├────────────────┤
   │ ...           │          │ ...            │            │ ...            │
   │               │          │                │            │                │
   └───────────────┘          └────────────────┘            └────────────────┘

Translation Lookaside Buffer

Виртуальная память создает иллюзию наличия большего объема памяти, чем физически доступно в вашей системе. Действительно, каждому процессу выделяется значительный объем этой виртуальной памяти. Физическая и виртуальная память разделены на сегменты фиксированной длины, называемые страницами.

Изображение от Michael Hausenblas

Изображение от Michael Hausenblas

Несколько различных процессов с помощью своих таблиц страниц могут сопоставить несколько виртуальных страниц с одной физической страницей. Это наглядно демонстрирует суть управления памятью — требуется эффективно создавать каждому процессу иллюзию присутствия его страницы в ОЗУ, оптимально используя доступное пространство.

Рассмотрим упрощенный пример:

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

  • Запускается второй процесс и пытается загрузить ту же программу. Ядро Linux распознает, что программа уже загружена в физическую память первым процессом

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

Всякий раз, когда ЦПУ необходимо получить доступ к виртуальной странице процесса, он должен транслировать виртуальный адрес в соответствующий физический адрес. Эта операция может быть многоуровневой и, следовательно, потенциально медленной. Для ускорения работы в современных процессорных архитектурах реализована встроенная функцию поиска — Translation Lookaside Buffer (TLB). TLB по сути является небольшим кешем. В случае отсутствия в нем информации для трансляции адреса виртуального адреса в физический, ЦПУ обращается к таблице страниц процесса и получает физический адрес страницы, после чего добавляет в TLB эту информацию

Изображение с core.vmware.com

Давайте рассмотрим пример того, как работает TLB:

  1. Процесс запрашивает доступ к данным, расположенным по определенному адресу виртуальной памяти, например 0x1111

  2. ЦПУ необходимо транслировать этот виртуальный адрес в физический. В первую очередь он проверит наличие информации для трансляции в TLB

  3. Предположим, что в TLB уже есть запись, которая сопоставляет 0x1111 в адрес физической памяти 0x2222

  4. ЦПУ может напрямую использовать физический адрес 0x2222 для доступа к данным в физической памяти, минуя обращение к таблице страниц

  5. Данные в адресе физической памяти 0x2222 могут быть использованы ЦПУ

Исторически Linux работал с размером страниц по умолчанию в 4 КБ. Однако начиная с версии ядра 2.6.3 была внедрена поддержка огромных страниц (huge pages), чтобы эффективнее адаптироваться к современным архитектурным решениям и рабочим нагрузкам.

Так, 64-разрядная версия Linux позволяет использовать до 128 ТБ виртуальной памяти для каждого процесса. Это теоретический максимум объема виртуальных адресов памяти, к которым можно получить доступ. Для физической памяти, которая соответствует установленной ОЗУ в вашем компьютере, 64-разрядный Linux может обработать в общей сложности около 64 ТБ.

В 64-разрядной системе теоретически можно выделить под адресацию 2⁶⁴ байт памяти. Однако в Linux для адресации используются только 48 бит, поэтому максимум составляет 2⁴⁸ байт, или 256 ТБ адресуемой памяти. Память разделена на пространство ядра и пользовательское пространство, причем пользовательское пространство занимает половину объема, что приводит к максимуму в 128 ТБ памяти на каждый процесс.

Ограничение физической памяти в 64 ТБ является результатом не теоретических, а архитектурных и практических ограничений. 64-разрядная адресация теоретически может обрабатывать экзабайты физической памяти, однако текущие возможности аппаратного обеспечения и реализация управления памятью Linux устанавливают практический предел в 64 ТБ.

Команды для анализа использования памяти

free

Команда free — это самая простая и понятная в использовании команда для проверки использования памяти в Linux:

$ free -h
total        used        free      shared  buff/cache   available
Mem:           15G        4.0G        7.8G        276M        3.2G         10G
Swap:         2.0G          0B        2.0G

top

Команда top показывает потребление ресурсов в режиме реального времени. Она может отображать сводную информацию о системе, а также список задач, которыми в данный момент управляет ядро Linux:

$ top
top - 13:11:34 up 10 days, 21:54,  1 user,  load average: 0.00, 0.01, 0.05
Tasks: 193 total,   1 running, 192 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.6 us,  0.2 sy,  0.0 ni, 99.1 id,  0.2 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 16223716 total,  7942444 free,  4375632 used,  3961640 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used. 11412212 avail Mem

htop

Команда htop похожа на top, но позволяет прокручивать вывод по вертикали и горизонтали, что обеспечивает удобный просмотр всех процессов, запущенных в системе, вместе с полными строками их команд.

vmstat

Команда vmstat показывает информацию о процессах, памяти, операциям ввода-вывода, работе диска и ЦПУ:

$ vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
1  0      0 7980008 103292 3814528    0    0    34    30  115  228  4  1 95  0  0

/proc/meminfo

Файл /proc/meminfo хранит статистику об использовании памяти в Linux системах:

$ cat /proc/meminfo
MemTotal:       16223716 kB
MemFree:         7940732 kB
MemAvailable:   11412272 kB
Buffers:          103292 kB
Cached:          2817920 kB
SwapCached:            0 kB
Active:          3200428 kB
Inactive:        2256692 kB

В случае обнаружения неточностей в переводе напишите, пожалуйста, в комментарии или мне в личные сообщения — исправим :)

© Habrahabr.ru