Поиск по сайту:

Как использовать команду pmap в Linux


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

Отображение памяти

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

Ядро поддерживает таблицу трансляции для каждого процесса, и ЦП обращается к ней. Когда ядро изменяет процесс, работающий на определенном ядре ЦП, оно обновляет таблицу преобразования, которая связывает процессы и ядра ЦП вместе.

Преимущества абстракции

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

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

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

ОЗУ по запросу

Таблица сопоставления и концепция «ОЗУ по требованию» открывают возможности разделяемой памяти. Ядро попытается избежать повторной загрузки одного и того же объекта в память. Например, он один раз загрузит разделяемую библиотеку в память и сопоставит ее с различными процессами, которые должны ее использовать. У каждого из процессов будет свой уникальный адрес общей библиотеки, но все они будут указывать на одно и то же фактическое местоположение.

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

Ядро Linux 2.6.32, выпущенное в декабре 2009 года, предоставило Linux функцию под названием «Слияние с ядром SamePage». Это означает, что Linux может обнаруживать идентичные области данных в разных адресных пространствах. Представьте себе серию виртуальных машин, работающих на одном компьютере, и все виртуальные машины работают под управлением одной и той же операционной системы. Используя модель с общей памятью и копирование при записи, накладные расходы на хост-компьютер могут быть значительно снижены.

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

Утилита pmap

Ядро раскрывает многое из того, что оно делает с оперативной памятью, через два псевдофайла в псевдофайловой системе системной информации «/proc». На каждый процесс приходится два файла, названных по идентификатору процесса или PID каждого процесса: «/proc/maps» и «/proc//smaps».

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

Поиск идентификатора процесса

Есть несколько способов узнать PID процесса. Вот исходный код простой программы, которую мы будем использовать в наших примерах. Он написан на C. Все, что он делает, — это выводит сообщение в окно терминала и ждет, пока пользователь нажмет клавишу «Enter».

#include <stdio.h>

int main(int argc, char *argv[])
{
  printf("How-To Geek test program.");
  getc(stdin);
} // end of main

Программа была скомпилирована в исполняемый файл с именем pm с помощью компилятора gcc:

gcc -o pm pm.c

Поскольку программа будет ждать, пока пользователь нажмет «Enter», она будет работать столько, сколько нам нужно.

./pm

Программа запускается, печатает сообщение и ждет нажатия клавиши. Теперь мы можем искать его PID. Команда ps выводит список запущенных процессов. Опция -e (показать все процессы) заставляет ps перечислять все процессы. Мы направим вывод через grep и отфильтруем записи, в названии которых есть «pm».

ps -e | grep pm

В нем перечислены все записи, в именах которых есть «pm».

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

pidof pm

Метод pidof удобнее, когда вы знаете имя процесса, но метод ps будет работать, даже если вы знаете только часть имени процесса.

Использование pmap

Когда наша тестовая программа запущена и мы определили ее PID, мы можем использовать pmap следующим образом:

pmap 40919

Отображения памяти для процесса перечислены для нас.

Вот полный вывод команды:

40919: ./pm
000056059f06c000      4K r---- pm
000056059f06d000      4K r-x-- pm
000056059f06e000      4K r---- pm
000056059f06f000      4K r---- pm
000056059f070000      4K rw--- pm
000056059fc39000    132K rw--- [ anon ]
00007f97a3edb000      8K rw--- [ anon ]
00007f97a3edd000    160K r---- libc.so.6
00007f97a3f05000   1616K r-x-- libc.so.6
00007f97a4099000    352K r---- libc.so.6
00007f97a40f1000      4K ----- libc.so.6
00007f97a40f2000     16K r---- libc.so.6
00007f97a40f6000      8K rw--- libc.so.6
00007f97a40f8000     60K rw--- [ anon ]
00007f97a4116000      4K r---- ld-linux-x86-64.so.2
00007f97a4117000    160K r-x-- ld-linux-x86-64.so.2
00007f97a413f000     40K r---- ld-linux-x86-64.so.2
00007f97a4149000      8K r---- ld-linux-x86-64.so.2
00007f97a414b000      8K rw--- ld-linux-x86-64.so.2
00007ffca0e7e000    132K rw--- [ stack ]
00007ffca0fe1000     16K r---- [ anon ]
00007ffca0fe5000      8K r-x-- [ anon ]
ffffffffff600000      4K --x-- [ anon ]
total              2756K

Первая строка — это имя процесса и его PID. Каждая из других строк показывает сопоставленный адрес памяти и объем памяти по этому адресу, выраженный в килобайтах. Следующие пять символов в каждой строке называются разрешениями на виртуальную память. Допустимые разрешения:

  • r: сопоставленная память может быть прочитана процессом.
  • w: отображаемая память может быть записана процессом.
  • x: процесс может выполнять любые инструкции, содержащиеся в отображаемой памяти.
  • s: сопоставленная память является общей, и изменения, внесенные в общую память, видны всем процессам, совместно использующим эту память.
  • R: для этой отображаемой памяти нет резервирования пространства подкачки.

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

Расширенный дисплей

Параметр -x (расширенный) предоставляет два дополнительных столбца.

pmap -x 40919

Столбцам даются заголовки. Мы уже видели столбцы «Адрес», «Кбайты», «Режим» и «Отображение». Новые столбцы называются «RSS» и «Грязный».

Вот полный вывод:

40919: ./pm
Address          Kbytes   RSS Dirty Mode  Mapping
000056059f06c000      4     4     0 r---- pm
000056059f06d000      4     4     0 r-x-- pm
000056059f06e000      4     4     0 r---- pm
000056059f06f000      4     4     4 r---- pm
000056059f070000      4     4     4 rw--- pm
000056059fc39000    132     4     4 rw--- [ anon ]
00007f97a3edb000      8     4     4 rw--- [ anon ]
00007f97a3edd000    160   160     0 r---- libc.so.6
00007f97a3f05000   1616   788     0 r-x-- libc.so.6
00007f97a4099000    352    64     0 r---- libc.so.6
00007f97a40f1000      4     0     0 ----- libc.so.6
00007f97a40f2000     16    16    16 r---- libc.so.6
00007f97a40f6000      8     8     8 rw--- libc.so.6
00007f97a40f8000     60    28    28 rw--- [ anon ]
00007f97a4116000      4     4     0 r---- ld-linux-x86-64.so.2
00007f97a4117000    160   160     0 r-x-- ld-linux-x86-64.so.2
00007f97a413f000     40    40     0 r---- ld-linux-x86-64.so.2
00007f97a4149000      8     8     8 r---- ld-linux-x86-64.so.2
00007f97a414b000      8     8     8 rw--- ld-linux-x86-64.so.2
00007ffca0e7e000    132    12    12 rw--- [ stack ]
00007ffca0fe1000     16     0     0 r---- [ anon ]
00007ffca0fe5000      8     4     0 r-x-- [ anon ]
ffffffffff600000      4     0     0 --x-- [ anon ]
---------------- ------- ------- ------- 
total kB           2756  1328    96

  • RSS: это резидентный размер набора. То есть объем памяти, которая в данный момент находится в ОЗУ и не выгружена.
  • Грязная: «грязная» память была изменена с момента запуска процесса и сопоставления.

Покажи мне все

-X (даже больше, чем расширенный) добавляет к выходным данным дополнительные столбцы. Обратите внимание на заглавную букву «X». Другая опция, называемая -XX (даже больше, чем -X), показывает вам все, что pmap может получить от ядра. Поскольку -X является подмножеством -XX, мы опишем вывод -XX.

pmap -XX 40919

Вывод ужасно обтекается в окне терминала и практически неразборчив. Вот полный вывод:

40919:   ./pm
         Address Perm   Offset Device  Inode Size KernelPageSize MMUPageSize  Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous LazyFree AnonHugePages ShmemPmdMapped FilePmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked THPeligible                 VmFlags Mapping
    56059f06c000 r--p 00000000  08:03 393304    4              4           4    4   4            0            0             4             0          4         0        0             0              0             0              0               0    0       0      0           0       rd mr mw me dw sd pm
    56059f06d000 r-xp 00001000  08:03 393304    4              4           4    4   4            0            0             4             0          4         0        0             0              0             0              0               0    0       0      0           0    rd ex mr mw me dw sd pm
    56059f06e000 r--p 00002000  08:03 393304    4              4           4    4   4            0            0             4             0          4         0        0             0              0             0              0               0    0       0      0           0       rd mr mw me dw sd pm
    56059f06f000 r--p 00002000  08:03 393304    4              4           4    4   4            0            0             0             4          4         4        0             0              0             0              0               0    0       0      0           0    rd mr mw me dw ac sd pm
    56059f070000 rw-p 00003000  08:03 393304    4              4           4    4   4            0            0             0             4          4         4        0             0              0             0              0               0    0       0      0           0 rd wr mr mw me dw ac sd pm
    56059fc39000 rw-p 00000000  00:00      0  132              4           4    4   4            0            0             0             4          4         4        0             0              0             0              0               0    0       0      0           0    rd wr mr mw me ac sd [heap]
    7f97a3edb000 rw-p 00000000  00:00      0    8              4           4    4   4            0            0             0             4          4         4        0             0              0             0              0               0    0       0      0           0    rd wr mr mw me ac sd 
    7f97a3edd000 r--p 00000000  08:03 264328  160              4           4  160   4          160            0             0             0        160         0        0             0              0             0              0               0    0       0      0           0          rd mr mw me sd libc.so.6
    7f97a3f05000 r-xp 00028000  08:03 264328 1616              4           4  788  32          788            0             0             0        788         0        0             0              0             0              0               0    0       0      0           0       rd ex mr mw me sd libc.so.6
    7f97a4099000 r--p 001bc000  08:03 264328  352              4           4   64   1           64            0             0             0         64         0        0             0              0             0              0               0    0       0      0           0          rd mr mw me sd libc.so.6
    7f97a40f1000 ---p 00214000  08:03 264328    4              4           4    0   0            0            0             0             0          0         0        0             0              0             0              0               0    0       0      0           0             mr mw me sd libc.so.6
    7f97a40f2000 r--p 00214000  08:03 264328   16              4           4   16  16            0            0             0            16         16        16        0             0              0             0              0               0    0       0      0           0       rd mr mw me ac sd libc.so.6
    7f97a40f6000 rw-p 00218000  08:03 264328    8              4           4    8   8            0            0             0             8          8         8        0             0              0             0              0               0    0       0      0           0    rd wr mr mw me ac sd libc.so.6
    7f97a40f8000 rw-p 00000000  00:00      0   60              4           4   28  28            0            0             0            28         28        28        0             0              0             0              0               0    0       0      0           0    rd wr mr mw me ac sd 
    7f97a4116000 r--p 00000000  08:03 264305    4              4           4    4   0            4            0             0             0          4         0        0             0              0             0              0               0    0       0      0           0       rd mr mw me dw sd ld-linux-x86-64.so.2
    7f97a4117000 r-xp 00001000  08:03 264305  160              4           4  160  11          160            0             0             0        160         0        0             0              0             0              0               0    0       0      0           0    rd ex mr mw me dw sd ld-linux-x86-64.so.2
    7f97a413f000 r--p 00029000  08:03 264305   40              4           4   40   1           40            0             0             0         40         0        0             0              0             0              0               0    0       0      0           0       rd mr mw me dw sd ld-linux-x86-64.so.2
    7f97a4149000 r--p 00032000  08:03 264305    8              4           4    8   8            0            0             0             8          8         8        0             0              0             0              0               0    0       0      0           0    rd mr mw me dw ac sd ld-linux-x86-64.so.2
    7f97a414b000 rw-p 00034000  08:03 264305    8              4           4    8   8            0            0             0             8          8         8        0             0              0             0              0               0    0       0      0           0 rd wr mr mw me dw ac sd ld-linux-x86-64.so.2
    7ffca0e7e000 rw-p 00000000  00:00      0  132              4           4   12  12            0            0             0            12         12        12        0             0              0             0              0               0    0       0      0           0    rd wr mr mw me gd ac [stack]
    7ffca0fe1000 r--p 00000000  00:00      0   16              4           4    0   0            0            0             0             0          0         0        0             0              0             0              0               0    0       0      0           0    rd mr pf io de dd sd [vvar]
    7ffca0fe5000 r-xp 00000000  00:00      0    8              4           4    4   0            4            0             0             0          4         0        0             0              0             0              0               0    0       0      0           0    rd ex mr mw me de sd [vdso]
ffffffffff600000 --xp 00000000  00:00      0    4              4           4    0   0            0            0             0             0          0         0        0             0              0             0              0               0    0       0      0           0                      ex [vsyscall]
                                             ==== ============== =========== ==== === ============ ============ ============= ============= ========== ========= ======== ============= ============== ============= ============== =============== ==== ======= ====== =========== 
                                             2756             92          92 1328 157         1220            0            12            96       1328        96        0             0              0             0              0               0    0       0      0           0 KB 

Здесь много информации. Вот что содержат столбцы:

  • Адрес: начальный адрес этого сопоставления. При этом используется адресация виртуальной памяти.
  • Пермь: разрешения памяти.
  • Смещение: если память файловая, смещение этого сопоставления внутри файла.
  • Устройство: номер устройства Linux, указанный в виде старшего и младшего номеров. Вы можете увидеть номера устройств на своем компьютере, выполнив команду lsblk.
  • Инод: индекс файла, с которым связано сопоставление. Например, в нашем примере это может быть индексный дескриптор, содержащий информацию о программе pm.
  • Размер: размер отображаемой в памяти области.
  • KernelPageSize: размер страницы, используемый ядром.
  • MMUPageSize: размер страницы, используемый блоком управления памятью.
  • Rss: это размер резидентного набора. То есть объем памяти, которая в данный момент находится в ОЗУ и не выгружена.
  • Pss: это пропорциональный размер доли. Это частный общий размер, добавленный к (общий размер, разделенный на количество общих ресурсов).
  • Shared_Clean: объем памяти, совместно используемой с другими процессами, который не изменился с момента создания сопоставления. Обратите внимание, что даже если память является общей, если она на самом деле не была общей, она все равно считается частной памятью.
  • Shared_Dirty: объем памяти, совместно используемой с другими процессами, которая была изменена с момента создания сопоставления.
  • Private_Clean: объем частной памяти, не используемой совместно с другими процессами, который не изменился с момента создания сопоставления.
  • Private_Dirty: объем частной памяти, которая была изменена с момента создания сопоставления.
  • Упомянутый: объем памяти, помеченный в настоящее время как указанный или доступный.
  • Анонимный: Память, в которой нет устройства для подкачки. То есть он не имеет резервной копии файла.
  • LazyFree: страницы, отмеченные как MADV_FREE. Эти страницы помечены как доступные для освобождения и восстановления, даже если на них могут быть неписаные изменения. Однако, если последующие изменения происходят после установки MADV_FREE в отображении памяти, флаг MADV_FREE снимается, и страницы не будут восстановлены до тех пор, пока изменения не будут записаны.< /li>
  • AnonHugePages: это «огромные» страницы памяти без файловой поддержки (больше 4 КБ).
  • ShmemPmdMapped: общая память, связанная с огромными страницами. Они также могут использоваться файловыми системами, полностью размещенными в памяти.
  • FilePmdMapped: средний каталог страниц — это одна из схем разбиения по страницам, доступных ядру. Это количество страниц с файловой поддержкой, на которые указывают записи PMD.
  • Shared_Hugetlb. Таблицы резервных копий перевода или TLB — это кэши памяти, используемые для оптимизации времени, необходимого для доступа к ячейкам памяти пользовательского пространства. Эта цифра представляет собой объем ОЗУ, используемый в TLB, связанных с общими огромными страницами памяти.
  • Private_Hugetlb: этот показатель представляет собой объем оперативной памяти, используемый в TLB, связанных с частными огромными страницами памяти.
  • Обмен: объем используемого обмена.
  • SwapPssпропорциональный размер доли обмена. Это объем подкачки, состоящий из замененных страниц частной памяти, добавленных к (общий размер, разделенный на количество общих ресурсов).
  • Заблокировано. Сопоставление памяти можно заблокировать, чтобы операционная система не выгружала память из кучи или вне кучи.
  • THPeligible: это флаг, указывающий, подходит ли сопоставление для выделения прозрачных огромных страниц. 1 означает истину, 0 означает ложь. Прозрачные огромные страницы – это система управления памятью, которая снижает нагрузку на поиск страниц TLB на компьютерах с большим объемом оперативной памяти.
  • VmFlags: см. список флагов ниже.
  • Mapping: имя источника сопоставления. Это может быть имя процесса, имя библиотеки или системные имена, такие как стек или куча.

VmFlags — флаги виртуальной памяти — будут подмножеством следующего списка.

  • rd: читаемый.
  • wr: Доступно для записи.
  • пример: исполняемый файл.
  • sh: общий доступ.
  • мистер: можно читать.
  • мужчина: Могу написать.
  • я: могу казнить.
  • мс: можно поделиться.
  • gd: сегмент стека уменьшается.
  • pf: чистый диапазон номеров фреймов страницы. Номера фреймов страниц — это список страниц физической памяти.
  • dw: запись в сопоставленный файл отключена.
  • lo: страницы заблокированы в памяти.
  • io: область ввода-вывода с отображением памяти.
  • sr: предоставляется совет по последовательному чтению (функция madvise().)
  • rr: дается совет о случайном прочтении.
  • dc: не копировать эту область памяти, если процесс разветвлен.
  • de: не расширять эту область памяти при переназначении.
  • ac: зона ответственности.
  • номер: пространство подкачки не зарезервировано для этой области.
  • ht: в Area используются огромные страницы TLB.
  • sf: Ошибка синхронной страницы.
  • ar: флаг, зависящий от архитектуры.
  • wf: очистить эту область памяти, если процесс разветвлен.
  • dd: не включать эту область памяти в дампы ядра.
  • sd: Мягкий грязный флаг.
  • мм: смешанная область карты.
  • hg: огромный флаг рекомендации страницы.
  • nh: нет пометки с предупреждением о большой странице.
  • mg: флаг объединения рекомендаций.
  • bt: страница, защищенная от нестабильности температуры смещения ARM64.
  • mt: теги расширения тегов памяти ARM64 включены.
  • гм: отсутствует отслеживание Userfaultfd.
  • uw: отслеживание Userfaultfd wr-protect.

Управление памятью сложно

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

Интересно отметить, что наша примерная программа скомпилирована в исполняемый двоичный файл размером 16 КБ, но при этом использует (или совместно использует) около 2756 КБ памяти, почти полностью из-за библиотек времени выполнения.

Еще одна хитрость заключается в том, что вы можете использовать команды pmap и pidof вместе, комбинируя действия по поиску PID процесса и передаче его в pmap в одну команду:

pmap $(pidof pm)