Понимание Linux /proc/id/maps

Я пытаюсь понять использование памяти встроенным приложением Linux. /proc/pid/maps Утилита / файл, кажется, хороший ресурс для просмотра деталей. К сожалению, я не понимаю все столбцы и записи.

Есть ли хороший ресурс / документация для proc/pid/maps утилита / файл?

Что означают анонимные записи inode 0? Похоже, это одни из самых больших сегментов памяти.

5 ответов

Решение

Каждый ряд в /proc/$PID/maps описывает область непрерывной виртуальной памяти в процессе или потоке. Каждая строка имеет следующие поля:

address           perms offset  dev   inode   pathname
08048000-08056000 r-xp 00000000 03:0c 64593   /usr/sbin/gpm
  • адрес - это начальный и конечный адрес региона в адресном пространстве процесса
  • permissions - описывает, как можно получить доступ к страницам в регионе. Существует четыре различных разрешения: чтение, запись, выполнение и совместное использование. Если чтение / запись / выполнение отключены, - появится вместо r/w/x, Если регион не является общим, он является частным, поэтому p появится вместо s, Если процесс пытается получить доступ к памяти способом, который не разрешен, генерируется ошибка сегментации. Разрешения могут быть изменены с помощью mprotect системный вызов.
  • смещение - если область была отображена из файла (используя mmap), это смещение в файле, где начинается отображение. Если память не была отображена из файла, это просто 0.
  • устройство - если область была сопоставлена ​​из файла, это основной и младший номер устройства (в шестнадцатеричном формате), в котором находится файл.
  • inode - если регион был отображен из файла, это номер файла.
  • pathname - если регион был отображен из файла, это имя файла. Это поле пустое для анонимных сопоставленных регионов. Есть также специальные регионы с такими именами, как [heap], [stack], или же [vdso], [vdso] обозначает виртуальный динамический общий объект. Он используется системными вызовами для переключения в режим ядра. Вот хорошая статья об этом.

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

proc(5)

mmap(2)

"Понимание ядра Linux" 9.3. Регионы памяти; 16,2. Отображение памяти

"Понимание диспетчера виртуальной памяти Linux" 4.4 Области памяти

Пожалуйста, проверьте: http://man7.org/linux/man-pages/man5/proc.5.html

address           perms offset  dev   inode       pathname
00400000-00452000 r-xp 00000000 08:02 173521      /usr/bin/dbus-daemon

Поле адреса - это адресное пространство в процессе, который занимает отображение.

Поле perms представляет собой набор разрешений:

 r = read
 w = write
 x = execute
 s = shared
 p = private (copy on write)

Поле смещения - это смещение в файл / что угодно;

dev - устройство (мажор: минор);

inode - это inode на этом устройстве.0 указывает, что ни один inode не связан с областью памяти, как в случае с BSS (неинициализированные данные).

Поле pathname обычно будет файлом, который поддерживает отображение. Для файлов ELF вы можете легко координировать свои действия с полем смещения, просматривая поле "Смещение" в заголовках программы ELF (readelf -l).

В Linux 2.0 нет поля с указанием пути.

Отображение памяти используется не только для отображения файлов в память, но также является инструментом для запроса оперативной памяти у ядра. Это те записи inode 0 - ваш стек, куча, сегменты bss и многое другое

Хотя в вопросе конкретно упоминаются встроенные системы, в заголовке упоминаются толькоproc/<pid>/maps, что также очень полезно для понимания «обычных» программ. В этом более широком контексте важно понимать, что память, выделенная пользователем, может оказаться либо в куче, либо в любом количестве анонимных сегментов памяти. Таким образом, большие блоки анонимной памяти, скорее всего, поступили из .

То, что называется «as», точнее, представляет собой непрерывную область между памятью, выделенной для статических переменных (называемой сегментом BSS ), и адресом, называемым «обрывом программы» (см. диаграмму ниже). Изначально эта область пуста и кучи нет. При вызове он может создать/расширить кучу, запросив ядро ​​— черезsyscall— для перемещения остановки программы. Аналогично, можно сжать кучу, если все адреса, прилегающие к разрыву программы, больше не используются.

Однако перенос перерыва в программе — не единственный способ освободить для себя больше места. Он также может запросить ядро ​​— черезsyscall— чтобы зарезервировать блок пространства где-то между стеком и кучей (см. диаграмму ниже). Память, выделенная таким образом, отображается как «анонимные записи индексного 0», упомянутые в вопросе.

Изображение предоставлено

Стоит немного остановиться на системном вызове. Существует четыре типа карт памяти, которые можно создавать, и каждый из них используется для совершенно разных целей. Во-первых, память может быть как привязана к содержимому определенного файла, так и нет. Последняя называется «анонимной» картой. Во-вторых, память может быть «частной» или «общей». Частный означает, что изменения, внесенные одним процессом, не будут видны другим; обычно это реализуется ленивым и эффективным способом, называемым « копированием при записи ». Общий означает, что каждый процесс получит доступ к одной и той же базовой физической памяти. Ниже приведены известные мне варианты использования каждого типа карты памяти:

Возвращаясь к , вы можете выяснить, какой тип карты памяти описывает каждая строка, просматривая столбцы «pathname» и «perms». (Эти имена столбцов взяты из ). Для карт файлов столбец «Имя пути» будет содержать фактический путь к сопоставляемому файлу. Для анонимных карт столбец «Путь» будет пустым. Существуют также некоторые специальные имена путей, например[heap]и[stack]. Для частных и общих карт столбец «разрешения» будет содержатьpилиsфлаг соответственно.

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

Вот соответствующий раздел изman malloc:

Обычно malloc() выделяет память из кучи и корректирует размер кучи по мере необходимости, используя sbrk(2). При выделении блоков памяти размером более MMAP_THRESHOLD байтов реализация glibc malloc() выделяет память как частное анонимное сопоставление с использованием mmap(2). По умолчанию размер MMAP_THRESHOLD составляет 128 КБ, но его можно настроить с помощью mallopt(3). До Linux 4.7 на выделения, выполняемые с помощью mmap(2), ограничение ресурса RLIMIT_DATA не влияло; начиная с Linux 4.7, это ограничение также применяется к выделениям, выполняемым с помощью mmap(2).

Подводя итог, если ваша программа использует , то, скорее всего, он отвечает за многие большие анонимные сегменты, которые отображаются в виртуальную память и о которых сообщает/proc/<pid>/maps.


Предостережение покупателя: практически все, что я здесь написал, я узнал только сегодня, так что относитесь к этому с недоверием. Тем не менее, вот ссылки на ресурсы, которые я нашел очень полезными для понимания всего этого:

Другие вопросы по тегам