Управление памятью в Linux

Обновлено: 29.06.2024

В настоящее время управление памятью Linux в системе SAP (сервере приложений) или системе SAP HANA становится все более важным, поскольку четкая дорожная карта SAP (Linux как единственная ОС для HANA) показывает, что количество установок Linux резко растет.< /p>

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

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

Наиболее распространенными системами Linux являются системы смешанного режима, использующие подкачку и подкачку.

Многие клиенты спрашивают меня в контексте мониторинга, правильно ли ведет себя система, когда объем используемой памяти близок к размеру физической памяти. Как вы, возможно, знаете, существует большая разница между концепцией памяти Unix и тем, как приложение обрабатывает свою память. Мониторинг памяти ОС совершенно бесполезен, если вы хотите использовать его для мониторинга систем HANA.

Наиболее известными инструментами являются top (по умолчанию), htop и nmon (содержится в большинстве репозиториев).

С помощью ps -ef или ps axu вы можете получить статическое представление о текущих процессах.

Но есть много информации о памяти, такой как VSZ/VSS (размер виртуального набора), RSS/RES (размер резидентного набора), SHR/SHM (общая память).

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

Мы начнем сверху вниз, чтобы получить некоторое представление.

  1. Полная системная память
    • Буфер
    • Кэш
    • Общая память
    • Плита
  2. Использование памяти отдельными процессами
  3. Сбор сведений о поддержке

Testsystem – это сервер приложений SLES12 SP4 объемом 16 ГБ с 20 рабочими процессами.

Полная системная память

Самый популярный способ увидеть полное потребление памяти — это команда:

Довольно просто объяснить:
Всего = физическая память,
Использовано = используемая память (включая буферы/кеши)
Общая = общая память (подробности см. раздел памяти)
Free = не выделенная память
Swap = занятое пространство подкачки на диске

  • Выделено 15,7 ГБ из 16 ГБ — свободно только 573 МБ
  • 7,5 ГБ из 16 ГБ используются буфером и кешем.

Реальный объем свободной памяти составляет 8810 МБ. Они получаются из свободных (573 МБ), буферов (174 МБ) и кэшированных (8062 МБ) => 573+174+8062 = ~8810 МБ

Кэш

С (Page)Cache and Buffers это то же самое, что и пейджинг и подкачка. Большинство людей путают эти термины.

Pagecache — это кэширование файловых данных. Когда файл читается с диска или из сети, его содержимое сохраняется в кэше страниц. Доступ к диску или сети не требуется, если содержимое кэша страниц обновлено.

Примечание: tmpfs и сегменты разделяемой памяти учитываются в кэше страниц!

Буфер

Кэш-буфер — это тип кэша страниц для блочных устройств (например, /dev/sda). Файловая система обычно использует буферный кеш при доступе к своим структурам метаданных на диске, таким как таблицы индексных дескрипторов, растровые изображения распределения и т. д. Buffercache можно восстановить так же, как и pagecache.

Эти 2 термина были разделены областями памяти в ядре Linux

Общая память

Концепция общей памяти широко используется рабочими процессами SAP. Каждому рабочему процессу требуется около 200-300 МБ выделенной памяти, даже когда они не активны. Большая часть памяти распределяется между процессами. Другая часть — это куча/рабочие данные.

Вы можете проверить это для всей системы с помощью:

=> Для сервера приложений значение общей памяти всегда велико — не беспокойтесь о том, что оно работает так, как задумано

Для каждого сегмента shm:

Для очистки некоторых зомби-процессов и сегментов общей памяти SAP представила бинарный cleanipc, который поставляется каждым ядром SAP AS. Обычно это делается при каждом чистом завершении работы.

Но вы можете активировать его самостоятельно:

Примечание. Не используйте его, когда система или любой из ее процессов все еще запущены и работают. Завершите все процессы и проверьте это с помощью ps -fu

Для систем SAP HANA RowStore также основан на концепции общей памяти. Это также причина, по которой эти таблицы не могут быть выгружены. Это одна из первых областей данных, которые считываются в память при запуске и удерживаются процессами hdbrsutil даже после остановки базы данных HANA.

Плита

– Выделение памяти для внутренних структур данных ядра –

В нормальных условиях эта область не должна занимать более 2 ГБ. Для небольших систем

Использование памяти отдельными процессами

Должен вас разочаровать, нет простого способа определить точное использование процесса без специальных инструментов или скриптов. Резидентная память (RSS) является хорошим индикатором реального использования, но она не включает выгруженную, неактивную память и общую память. Ближайшее значение — PSS (Proportional Set Size). Никогда не слышали об этом термине? Это новая концепция измерения.

ВСЗ/ВСС:

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

ВИРТ / ВСЗ / ВСС = СВАП + РЕС

RSS/RES:

Физическая память без подкачки, которую использовала задача (включая общую память)

RES = КОД + ДАННЫЕ + SHM.

То же, что и RSS, но общая память будет отслеживаться как доля, используемая текущим процессом.

PSS = КОД + ДАННЫЕ + SHM/

< бр />

Но как определить такие значения? Вы можете сделать это вручную с помощью /proc/

/smaps, но в зависимости от процесса и областей его распределения это может быть долгий анализ.

Быстрый и грязный анализ (изменить значение PID):

Для подробного анализа я рекомендую несколько скриптов:

Лично я использую первый, потому что лучше знаком с python как с perl. С помощью этих скриптов вы можете анализировать один процесс (=PID).

Итак, я написал небольшой сценарий оболочки для анализа более чем одного PID. Обычно требуется проанализировать всю систему SAP, включающую все рабочие процессы.

Код для бесплатного использования:

просто отредактируйте путь к скрипту Python, который вы уже скачали ранее.

  1. скачать скрипт Python linux_smap_analyzer.py
  2. создать сценарий bash с правами на выполнение, включая содержимое выше
  3. изменить путь в скрипте bash
  4. запустить его с поисковым запросом и выходным путем

«dw.sap» — это краткий термин для процессов disp+work, но вы также можете использовать PID или другой термин, используемый вашим приложением.

Вот пример вывода рабочего процесса 6 (W6) системы с именем «SID» и номером экземпляра «00»:

Подводя итоги этого процесса:

map Pss total = 720927 КБ => 720 МБ
map Vss total = 12039104 КБ => 12000 МБ
=> что означает, что около 11,3 ГБ занимают SHM (в большинстве случаев) или подкачка

Чтобы проанализировать группу процессов в одном выходном файле:

Это означает, что системе с 20 рабочими процессами в настоящее время требуется около 9,8 ГБ памяти.

Сбор сведений о поддержке

Для создания всей необходимой информации для поддержки SAP/Linux запустите скрипт sapsysinfo.sh, прикрепленный к примечанию 618104.

Кроме того, вы можете создать сведения для SLES с помощью команд supportconfig и sosreport для RHEL.

Примечание. Пожалуйста, немедленно запустите эти инструменты сбора данных, во всех остальных случаях уже слишком поздно реконструировать сценарий и то, что является реальной основной причиной вашего потребления памяти!

Обзор

Надеюсь, вы смогли получить некоторое представление об управлении памятью. Отличия подкачки, пейджинга, буфера и кешей и VSZ(VSS)/RSS/PSS. Это поможет вам правильно оценить размер вашей системы и понять возможные узкие места. Есть масса других подробностей, но для большинства фанатов Linux это должно стать хорошей отправной точкой для лучшего понимания управления памятью.

Управление памятью в Linux

В этой статье мы рассмотрим основные команды для управления памятью в Linux. Управление памятью — обширная тема, и осветить ее в одном посте в блоге не получится. В этом руководстве мы в основном рассмотрим команды, которые вы можете использовать для наблюдения за статистикой использования памяти.

Оглавление

Физическая и виртуальная память в Linux

Прежде чем мы углубимся в детали, важно знать, что в Linux есть два типа памяти.

Физическая память — это фактическая память, присутствующая в машине. Хотя виртуальная память — это слой адресов памяти, которые сопоставляются с физическими адресами.

Виртуальная память обычно больше физической.

Ядро Linux использует виртуальную память, чтобы программы могли резервировать память.

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

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

Давайте рассмотрим некоторые команды для управления памятью в Linux.

1. /proc/meminfo

Файл /proc/meminfo содержит всю информацию, связанную с памятью. Для просмотра этого файла используйте команду cat:

Meminfo

Эта команда выводит множество параметров, связанных с памятью. Чтобы получить физическую память из файла proc/meminfo, используйте:

Memtotal

Чтобы получить виртуальную память из файла /proc/meminfo, используйте:

VmallocTotal

2. Верхняя команда

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

Top

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

3. бесплатная команда

Команда free отображает объем свободной и используемой памяти в системе. Это простая и компактная команда для использования. Он сообщает вам информацию, например, сколько свободной оперативной памяти у вас есть в вашей системе. Он также сообщает вам об общем объеме физической памяти и памяти подкачки в вашей системе.

Free

Значения для каждого поля указаны в кибибайтах (КиБ). Кибибайт — это не то же самое, что килобайт. Чтобы получить вывод в более удобном для человека формате, используйте:

Free 0h

Чтобы узнать больше о команде free, обратитесь к нашему руководству, в котором подробно обсуждается команда free.

4. команда vmstat

vmstat – это инструмент для мониторинга производительности в Linux. Он дает полезную информацию о процессах, памяти, блочном вводе-выводе, подкачке, диске и планировании ЦП. Он сообщает статистику виртуальной памяти вашей системы.

Vmstat

Чтобы узнать больше о команде vmstat в Linux, обратитесь к руководству по vmstat.

Заключение

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

В этой статье я собираюсь описать некоторые общие и некоторые особенности управления памятью в Linux. В основном это будет динамическое выделение и освобождение памяти, а также управление свободной памятью. Статья касается версий ядра Linux 2.6.X.

Структура управления памятью в Linux

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

Службы управления памятью в Linux построены на основе программирования, которая включает периферийное устройство, называемое блоком управления памятью (MMU). MMU преобразует адреса физической памяти в линейные адреса, используемые операционной системой, и запрашивает прерывание по ошибке страницы, когда ЦП пытается получить доступ к памяти, на которую он не имеет права.

Не все процессоры имеют MMU. Поэтому дистрибутив uClinux (Linux для микроконтроллеров) поддерживает единое адресное пространство работы. В этой архитектуре отсутствует защита, обеспечиваемая MMU, но она позволяет Linux работать на процессорах другого класса.

Для дальнейшего понимания структуры служб MM нам необходимо знать, что основной единицей памяти в Linux является страница, непересекающаяся область непрерывной памяти.Вся доступная физическая память организована в страницы ближе к концу процесса загрузки ядра. Размер страницы зависит от архитектуры процессора. Конструкции процессоров часто позволяют иметь два или более размеров страницы, иногда одновременно.

Традиционный размер страницы, используемый Linux, составляет 4096 байт.

Но использовать страницы памяти «как есть» не очень удобно. Часто нам нужно выделить меньше одной страницы памяти. В Linux есть такие возможности:

  • в ядре вы можете выделить один из небольших объектов ядра, используя slab allocator;
  • вы можете выделить блок памяти с помощью kmalloc, но он выделит только блок ближайшего большего размера, чем у него есть;
  • в пользовательском режиме можно выделить любой объем памяти с помощью функций управления кучей, реализованных в стандартной библиотеке C;
  • вы можете создать собственный диспетчер кучи поверх системных вызовов ядра Linux.
  • Распределитель блоков
  • Распределитель зон
  • Распределитель друзей

Общая схема взаимодействия всех этих слоев с кодом пользовательского режима и оборудованием выглядит следующим образом:

i1

Рисунок 1. Общая схема управления памятью в Linux

Обратите внимание, что в Linux большинство программ прямо или косвенно используют диспетчер кучи стандартной библиотеки C GCC, называемый glibc, но вы все равно можете написать свой собственный диспетчер кучи поверх системных вызовов ядра.

Как видно из рисунка 1, выделение пользовательского пространства всегда приводит к выделению ядра. Ядро выделяет память, используя цепочку из трех распределителей ядра, и сопоставляет выделенные страницы с адресным пространством процесса, запросившего выделение.

Службы управления памятью в режиме ядра

Распределитель друзей отвечает за управление распределением страниц во всей системе. Этот код управляет списками физически смежных страниц и сопоставляет их с таблицами страниц MMU, чтобы предоставить другим подсистемам ядра допустимые диапазоны физических адресов, когда ядро ​​их запрашивает (сопоставление физического и виртуального адресов обрабатывается более высоким уровнем виртуальной машины).

i2

Рисунок 2. Массив списков страниц памяти в Buddy Allocator

Каждый список состоит из свободных физически смежных блоков из 2i страниц памяти, где i — номер списка. Каждый из таких блоков, кроме блока, состоящего из 1 страницы, можно разделить на две половины и использовать как 2 блока половинного размера.

Поэтому, если в запрошенном списке нет записей, запись из следующего верхнего списка разбивается на два отдельных кластера, и один возвращается вызывающей стороне, а другой добавляется в следующий нижний список.

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

Когда выделение возвращается в Распределитель друзей, он проверяет, свободен ли партнер распределения, и если это так, Распределитель друзей объединяет их в больший блок. Эта операция повторяется до тех пор, пока не будет найдено больше друзей по блоку.

Также следует отметить, что Buddy Allocator может выделять на страницах только блоки такого размера, который равен 2 в некоторой степени.

Buddy Allocator также взаимодействует с потоками ядра kswapd и bdflush, которые отвечают за поддержку свопа.

Различные диапазоны физических страниц могут иметь разные свойства для целей ядра. Например, прямой доступ к памяти может работать только в определенном диапазоне физических адресов в архитектуре x86. С другой стороны, PPC не имеет этого ограничения.

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

Распределитель зон используется для распределения страниц в указанной зоне. Сегодня ядро ​​Linux поддерживает три зоны памяти:

  • DMA – эта зона состоит из памяти, доступной для прямых операций с памятью устаревших устройств.
  • НОРМАЛЬНАЯ. Эта зона включает адреса памяти, используемые ядром для внутренних структур данных, а также для других системных и пользовательских выделений пространства.
  • HIGHMEM – эта зона включает всю память, используемую исключительно для системных выделений (буферы файловой системы, выделенное пространство пользователя и т. д.).

Обратите внимание, что распределитель зон также может работать только со страницами памяти.

Поскольку нам часто приходится выделять объекты, размер которых меньше размера страницы, нам нужно что-то, чтобы обрабатывать страницы и выделять для нас меньшие фрагменты памяти.

Мы знаем размеры большинства объектов, которые часто выделяются в пространстве ядра, поэтому мы можем создать распределитель, который будет получать страницы памяти из Распределителя зон и размещать в этих страницах памяти небольшие объекты. Эта подсистема называется Slab Allocator (Распределитель памяти ядра с кэшированием объектов).

Slab Allocator распределяет память в кэшах, по одному кэшу для каждого типа объекта, например. inode_cache, dentry_cache, buffer_head, vm_area_struct. Каждый кеш состоит из множества блоков (обычно длиной в одну страницу), и каждый блок содержит несколько инициализированных объектов.

Это означает, что конструктор объектов используется только для вновь выделенных блоков, и вы должны инициализировать объект, прежде чем передавать его в Распределитель блоков.

Кроме того, ядро ​​может выделять виртуально непрерывную память (память с непрерывными виртуальными адресами, но не с непрерывными физическими адресами) с помощью функции vmalloc.

Особенности механизмов управления памятью ядра Linux

Почему разработчики Linux редко проверяют результаты выделения памяти.

Короткий ответ: "Из-за чрезмерной фиксации".

Согласно стратегии управления памятью по умолчанию, malloc (а также kmalloc и vmalloc) всегда завершается успешно, даже если в системе недостаточно памяти для удовлетворения запроса. Ядро Linux предполагает, что вы не собираетесь использовать всю запрошенную память. Реальное распределение происходит только тогда, когда вы получаете доступ к выделенной памяти, и если в системе недостаточно свободной памяти, она запустит убийцу нехватки памяти (OOM). OOM killer попытается освободить для вас часть памяти, уничтожив другие процессы и освободив их память, или уничтожит ваш процесс, если сочтет, что выполняемая вами задача имеет более низкий приоритет.

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

Но иногда такой подход не годится из-за шанса быть убитым OOM killer в любой момент. К счастью, Linux позволяет изменить подход по умолчанию к выделению памяти и поведению системы при возникновении события OOM.

Политика overcommit задается через sysctl vm.overcommit_memory .

Ядро Linux поддерживает следующие режимы обработки избыточной фиксации, связанные со значениями параметра ядра vm.overcommit_memory :

0 – эвристическая обработка избыточной фиксации. Очевидные превышения адресного пространства запрещены. Этот тип обработки используется для типичной системы. Это гарантирует сбой серьезного дикого распределения, позволяя уменьшить использование подкачки. В этом режиме пользователю root разрешено выделять немного больше памяти. Этот тип установлен по умолчанию.

1 – Всегда перегружаться. Подходит для некоторых научных приложений, использующих много памяти.

2 – Не переусердствуйте. Общее выделение адресного пространства для системы не может превышать объем подкачки + настраиваемый процент (по умолчанию 50%) физического ОЗУ. В зависимости от того, какой процент вы используете, в большинстве ситуаций это означает, что процесс не будет остановлен при доступе к страницам, но будет получать ошибки при выделении памяти по мере необходимости.

Процент чрезмерной фиксации устанавливается с помощью sysctrl vm.overcommit_ratio .

Текущий предел перерасхода и зафиксированная сумма могут быть просмотрены в /proc/meminfo как CommitLimit и Committed_AS соответственно.

Как работает механизм устранения нехватки памяти

Существует три способа справиться с ситуацией нехватки памяти:

  • Завершить процесс выделения
  • Убить какой-либо другой процесс или процессы, чтобы позволить процессу выделить память
  • Остановить систему и показать сообщение о панике ядра.

Первая и третья стратегии довольно просты, в отличие от второй стратегии. Рассмотрим его подробнее.

В соответствии со второй стратегией Linux попытается выбрать подходящий процесс для уничтожения, когда ему не хватит памяти. «Соответствующий» в данном контексте означает, что:

  • Пользователь потеряет минимальный объем выполненной работы.
  • Система восстановит большой объем памяти.
  • Убийца OOM не уничтожает процесс, которому не выделено много памяти
  • OOM killer предназначен для уничтожения минимального количества процессов (лучше всего убить только один процесс)
  • Убийца OOM уничтожит процесс, которого ожидает пользователь.

Чтобы выбрать процесс для уничтожения, OOM killer вычисляет значение Badness. Затем он выбирает процесс с максимальным Badness для уничтожения. Если был выбран процесс выделения, OOM прекращает свою работу. Если был выбран какой-либо другой процесс, убийца OOM может быть вызван более одного раза, если предыдущий запуск убийцы OOM не освободил достаточно памяти.

Плохость рассчитывается по следующим правилам:

  • Исходная неисправность процесса A равна размеру выделенной для него виртуальной памяти плюс половина размера виртуальной памяти, выделенной дочерним процессам процесса A;
  • Первоначальная неисправность делится на квадратный корень из времени ЦП, потребляемого процессом A, измеряемого в десятках секунд;
  • Результат делится на корень с индексом 4 времени выполнения процесса A, измеряемого в тысячах секунд.
  • Если у процесса А "хороший" больше нуля (приоритет ниже нормального), то "плохой" процесс А умножается на 2;
  • Если процесс A был запущен с привилегиями root, степень вредоносности процесса A делится на 4;
  • Если процесс A выполняет необработанный ввод-вывод, степень ошибки процесса A делится на 4;
  • Если использование памяти процессом A может не повлиять на память, доступную процессу, который инициировал процедуру OOM, то степень недопустимости процесса A делится на 8;

Плохость процесса A можно записать в виде уравнения:

i3

i4< бр />

if_nice может принимать значение 1 или 2 в зависимости от значения nice процесса (2, если nice > 2 или 1 в противном случае)
if_root может принимать значение 1 или 4 (4, если процесс A имеет привилегии root, или 1 в противном случае)
if_raw_io может быть 1 или 4 (4, если процесс может выполнять необработанный ввод-вывод или 1 в противном случае)
< em>if_memory_does_not_overlap может быть 1 или 8 ( 8, если у процесса A нет памяти, которую можно выделить процессу, который инициировал процедуру OOM).

Вы можете увидеть механизм обработчика нехватки памяти в исходном файле «/mm/oom_kill.c» в дереве исходных текстов ядра Linux.

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

Этот параметр позволяет создавать общесистемный дамп задачи (за исключением потоков ядра), когда ядро ​​выполняет уничтожение OOM, и включает такую ​​информацию, как pid, uid, tgid, размер vm, rss, cpu, оценка oom_adj и имя. Полезно определить, почему был вызван убийца OOM, и определить процесс, вызвавший его.

Если установлено нулевое значение, эта информация скрыта.

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

По умолчанию для vm.oom_dump_tasks установлено значение 1;

Этот параметр включает или отключает уничтожение задачи, запускаемой OOM, в случае нехватки памяти.

Если для этого параметра задано ненулевое значение, убийца OOM просто уничтожает задачу, вызвавшую нехватку памяти. Это помогает избежать ресурсоемкого сканирования списка задач и делает убийцу OOM очень предсказуемым.

Если установлено нулевое значение, убийца OOM просканирует весь список задач и выберет задачу на основе расчета критичности.

По умолчанию для vm.oom_kill_allocating_task установлено значение 0;

Если для этого параметра ядра установлено значение 1, при нехватке памяти возникает паника ядра. Но если процесс ограничен узлами с помощью mempolicy/cpusets, и эти узлы получают статус исчерпания памяти, один процесс может быть убит убийцей OOM. В этом случае не происходит паники ядра, поскольку другие узлы памяти могут быть свободны.

Если для этого параметра установлено значение 2, паника ядра вызывается даже в вышеупомянутой ситуации. Даже если OOM происходит в контрольной группе памяти, вся система паникует.

Если для этого параметра установлено значение 0, ядро ​​остановит некоторые процессы, когда произойдет OOM.

По умолчанию для vm.panic_on_oom установлено значение 0;

Обратите внимание, что panic_on_oom имеет более высокий приоритет, чем oom_kill_allocating_task.

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

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

2.1. Пейджинг по требованию

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

Обзор Red Hat Enterprise Linux для системы виртуальной памяти реального времени

Рисунок 2.1. Red Hat Enterprise Linux для системы виртуальной памяти реального времени

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

Когда записи в таблице страниц присвоен физический адрес, она называется резидентным рабочим набором. Когда операционной системе необходимо освободить память для других процессов, она может удалить страницы из рабочего набора. Когда это произойдет, любая ссылка на виртуальный адрес на этой странице вызовет ошибку страницы, и страница будет перераспределена. Если в системе очень мало физической памяти, этот процесс начнет зависать, постоянно крадя страницы из процессов и никогда не позволяя процессу завершиться. Статистику виртуальной памяти можно отслеживать, найдя значение pgfault в файле /proc/vmstat.

TLB — это аппаратные кэши трансляций виртуальной памяти. Любое ядро ​​процессора с TLB будет проверять TLB параллельно с инициированием чтения из памяти записи таблицы страниц. Если запись TLB для виртуального адреса действительна, чтение памяти прерывается и значение в TLB используется для преобразования адреса.

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

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

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

При написании многопоточного приложения важно учитывать топологию компьютера при разработке декомпозиции данных. Топология — это иерархия памяти, включающая кэши ЦП и узел NUMA. Слишком тесный обмен информацией о данных между ЦП в разных кэшах и доменах NUMA может привести к проблемам с трафиком и узким местам.

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

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

Пример 2.1. Использование файла /proc/PID/stat для проверки ошибок страницы

Используйте команду cat и функцию конвейера, чтобы вернуть только вторую, десятую и двенадцатую строки файла /proc/PID/stat:

В приведенном выше выводе PID 3366 — это bash , и он сообщил о 5389 незначительных ошибках страниц и об отсутствии серьезных ошибок страниц.

Примечание

Для получения дополнительной информации или для дальнейшего чтения следующая книга связана с информацией, приведенной в этом разделе:

Читайте также: