如何在 Linux 上使用 pmap 命令如何在 Linux 上使用 pmap 命令如何在 Linux 上使用 pmap 命令如何在 Linux 上使用 pmap 命令
  • 文章
  • 正则表达式
    • 工具
  • 登录
找到的结果: {phrase} (显示: {results_count} 共: {results_count_total})
显示: {results_count} 共: {results_count_total}

加载更多搜索结果...

搜索范围
模糊匹配
搜索标题
搜索内容
发表 admin at 2025年2月28日
类别
  • 未分类
标签

如何在 Linux 上使用 pmap 命令

找出一个 Linux 进程使用了多少 RAM 并不是一件简单的事情——尤其是在需要考虑共享内存的时候。值得庆幸的是,pmap 命令可以帮助您理解这一切。

内存映射

在现代操作系统中,每个进程都位于自己分配的内存区域或分配空间中。分配区域的边界不直接映射到物理硬件地址。操作系统为每个进程创建一个虚拟内存空间,并充当将虚拟内存映射到物理内存的抽象层。

内核为每个进程维护一个转换表,并由 CPU 访问。当内核更改在特定 CPU 核心上运行的进程时,它会更新将进程和 CPU 核心联系在一起的转换表。

抽象的好处

这个方案有好处。对于用户空间中的每个进程,内存的使用在某种程度上被封装和沙盒化。进程仅根据虚拟内存地址“看到”内存。这意味着它只能使用操作系统提供的内存。除非它可以访问某些共享内存,否则它既不知道也无法访问分配给其他进程的内存。

将基于硬件的物理内存抽象为虚拟内存地址,使内核可以更改某些虚拟内存映射到的物理地址。它可以通过更改虚拟内存区域指向的实际地址来将内存交换到磁盘。它还可以推迟提供物理内存,直到实际需要为止。

只要读取或写入内存的请求按要求得到服务,内核就可以随意调整映射表,因为它认为合适。

按需分配内存

映射表和“RAM on demand”的概念开启了共享内存的可能性。内核会尽量避免将相同的东西多次加载到内存中。例如,它会将一个共享库加载到内存中一次,并将其映射到需要使用它的不同进程。每个进程都有自己唯一的共享库地址,但它们都指向相同的实际位置。

如果共享内存区域是可写的,则内核使用一种称为写时复制的方案。如果一个进程写入共享内存,而共享该内存的其他进程不应该看到更改,则在写入请求时创建共享内存的副本。

2009 年 12 月发布的 Linux 内核 2.6.32 为 Linux 提供了一项名为“Kernel SamePage Merging”的功能。这意味着 Linux 可以检测不同地址空间中的相同数据区域。想象一下在一台计算机上运行一系列虚拟机,并且虚拟机都运行相同的操作系统。使用共享内存模型和写时复制,可以大大减少主机上的开销。

所有这些都使得 Linux 中的内存处理变得复杂并且尽可能地优化。但是这种复杂性使得很难查看进程并了解其内存使用情况。

pmap 实用程序

内核通过“/proc”系统信息伪文件系统中的两个伪文件公开了它对 RAM 所做的很多事情。每个进程有两个文件,以每个进程的进程 ID 或 PID 命名:“/proc/maps”和“/proc//smaps”。

pmap 工具从这些文件中读取信息并在终端窗口中显示结果。很明显,每当我们使用 pmap 时,我们都需要提供我们感兴趣的进程的 PID。

查找进程 ID

有几种方法可以找到进程的 PID。这是我们将在示例中使用的一个简单程序的源代码。它是用 C 语言编写的。它所做的只是向终端窗口打印一条消息并等待用户按下“Enter”键。

#include <stdio.h>

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

该程序使用 gcc 编译器编译为名为 pm 的可执行文件:

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”和“Dirty”。

这是完整的输出:

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:这是驻留集大小。也就是说,当前位于 RAM 中且未换出的内存量。
  • 脏:“脏”内存自进程和映射启动以来已更改。

给我看一切

-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 

这里有很多信息。这是列的内容:

  • 地址:该映射的起始地址。这使用虚拟内存寻址。
  • Perm:内存的权限。
  • Offset:如果内存是基于文件的,则此映射在文件中的偏移量。
  • Device:Linux 设备号,以主要和次要编号给出。您可以通过运行 lsblk 命令查看计算机上的设备编号。
  • Inode:与映射关联的文件的 inode。例如,在我们的示例中,这可能是保存有关 pm 程序的信息的 inode。
  • 大小:内存映射区域的大小。
  • KernelPageSize:内核使用的页面大小。
  • MMUPageSize:内存管理单元使用的页面大小。
  • Rss:这是驻留集大小。也就是说,当前位于 RAM 中且未换出的内存量。
  • Pss:这是比例份额。这是添加到(共享大小除以共享数量)的私有共享大小。
  • Shared_Clean:自映射创建以来未更改的与其他进程共享的内存量。请注意,即使内存是可共享的,如果它实际上没有被共享,它仍然被认为是私有内存。
  • Shared_Dirty:自映射创建以来已更改的与其他进程共享的内存量。
  • Private_Clean:自映射创建以来未更改的私有内存量(未与其他进程共享)。
  • Private_Dirty:自映射创建以来已更改的私有内存量。
  • 已引用:当前标记为已引用或已访问的内存量。
  • Anonymous:没有可换出设备的内存。也就是说,它没有文件支持。
  • LazyFree:已标记为 MADV_FREE 的页面。这些页面已被标记为可供释放和回收,即使它们可能有未写入的更改。但是,如果在内存映射上设置了 MADV_FREE 之后发生后续更改,则会删除 MADV_FREE 标志,并且在写入更改之前不会回收页面。< /李>
  • AnonHugePages:这些是非文件支持的“巨大”内存页面(大于 4 KB)。
  • ShmemPmdMapped:与大页面关联的共享内存。它们也可以被完全驻留在内存中的文件系统使用。
  • FilePmdMapped:页面中间目录是内核可用的分页方案之一。这是 PMD 条目指向的文件支持页面的数量。
  • Shared_Hugetlb:翻译后备表或 TLB 是内存缓存,用于优化访问用户空间内存位置所花费的时间。这个数字是在与共享大内存页面相关联的 TLB 中使用的 RAM 量。
  • Private_Hugetlb:这个数字是在与私有大内存页关联的 TLB 中使用的 RAM 量。
  • Swap:正在使用的交换量。
  • SwapPss:交换比例份额大小。这是由添加到(共享大小除以共享数)的交换专用内存页组成的交换量。
  • 锁定:可以锁定内存映射以防止操作系统调出堆或堆外内存。
  • THPeligible:这是一个标志,指示映射是否符合分配透明大页面的条件。 1 表示真,0 表示假。透明大页面是一种内存管理系统,可减少在具有大量 RAM 的计算机上查找 TLB 页面的开销。
  • VmFlags:请参阅下面的标志列表。
  • Mapping:映射源的名称。这可以是进程名称、库名称或系统名称,例如堆栈或堆。

VmFlags——虚拟内存标志——将是以下列表的一个子集。

  • rd:可读。
  • wr:可写。
  • ex:可执行。
  • sh:共享。
  • 先生:可以阅读。
  • mw:可以写。
  • 我:可以执行。
  • ms:可以分享。
  • gd:堆栈段向下增长。
  • pf:纯页框编号范围。页框编号是物理内存页的列表。
  • dw:禁止写入映射文件。
  • lo:页面被锁定在内存中。
  • io:内存映射I/O区。
  • sr:提供顺序阅读建议(由 madvise() 函数提供。)
  • rr:提供随机阅读建议。
  • dc:如果进程被分叉,则不要复制此内存区域。
  • de:不要在重新映射时扩展此内存区域。
  • ac:区域负责。
  • nr:Swap空间未预留给该区域。
  • ht:区域使用巨大的 TLB 页面。
  • sf:同步页面错误。
  • ar:特定于体系结构的标志。
  • wf:如果进程被分叉,则擦除此内存区域。
  • dd:不要在核心转储中包含此内存区域。
  • sd:软脏标志。
  • mm:混合地图区域。
  • hg:大页面建议标志。
  • nh:没有大页面建议标志。
  • mg:可合并建议标志。
  • bt:ARM64 偏置温度不稳定受保护页面。
  • mt:启用 ARM64 内存标记扩展标记。
  • 嗯:Userfaultfd 缺少跟踪。
  • uw:Userfaultfd wr-protect 跟踪。

内存管理很复杂

从数据表逆向分析以了解实际情况是很困难的。但至少 pmap 为您提供了全貌,因此您有最好的机会弄清楚您需要了解的内容。

有趣的是,我们的示例程序编译为 16 KB 的二进制可执行文件,但它使用(或共享)大约 2756 KB 的内存,几乎完全是由于运行时库。

最后一个巧妙的技巧是,您可以同时使用 pmap 和 pidof 命令,结合查找进程的 PID 并将其传递给 pmap 变成一个命令:

pmap $(pidof pm)
©2015-2025 艾丽卡 support@alaica.com