/proc/PID/maps 文件及示例说明

发布时间 2023-08-17 17:28:34作者: 武平宁

文件及字段说明

这个文件中的内容描述了进程的虚拟内存空间中的不同区域,包括代码段、数据段、堆、栈以及共享库等。
每一行都代表了一个内存区域,并包含以下列:

起始地址和结束地址:内存区域在虚拟内存空间中的起始地址和结束地址。
权限:内存区域的访问权限,如读、写、执行等。
偏移量:内存区域相对于文件的偏移量。对于匿名内存区域,它通常为0。
设备号:如果内存区域映射的是文件,那么设备号表示文件所在的设备。
节点号:如果内存区域映射的是文件,那么节点号表示文件的索引节点号。
文件名:内存区域映射的文件的路径名。对于匿名内存区域,它通常为[heap]或[stack]。

一个bash进程的例子

00400000-004de000 r-xp 00000000 fd:00 50548532                           /usr/bin/bash
006dd000-006de000 r--p 000dd000 fd:00 50548532                           /usr/bin/bash
006de000-006e7000 rw-p 000de000 fd:00 50548532                           /usr/bin/bash
006e7000-006ed000 rw-p 00000000 00:00 0 
01e31000-01e94000 rw-p 00000000 00:00 0                                  [heap]
7f2c0d369000-7f2c138ac000 r--p 00000000 fd:00 50548497                   /usr/lib/locale/locale-archive
7f2c138ac000-7f2c138b8000 r-xp 00000000 fd:00 15685                      /usr/lib64/libnss_files-2.17.so
7f2c138b8000-7f2c13ab7000 ---p 0000c000 fd:00 15685                      /usr/lib64/libnss_files-2.17.so
7f2c13ab7000-7f2c13ab8000 r--p 0000b000 fd:00 15685                      /usr/lib64/libnss_files-2.17.so
7f2c13ab8000-7f2c13ab9000 rw-p 0000c000 fd:00 15685                      /usr/lib64/libnss_files-2.17.so
7f2c13ab9000-7f2c13abf000 rw-p 00000000 00:00 0 
7f2c13abf000-7f2c13c83000 r-xp 00000000 fd:00 15672                      /usr/lib64/libc-2.17.so
7f2c13c83000-7f2c13e82000 ---p 001c4000 fd:00 15672                      /usr/lib64/libc-2.17.so
7f2c13e82000-7f2c13e86000 r--p 001c3000 fd:00 15672                      /usr/lib64/libc-2.17.so
7f2c13e86000-7f2c13e88000 rw-p 001c7000 fd:00 15672                      /usr/lib64/libc-2.17.so
7f2c13e88000-7f2c13e8d000 rw-p 00000000 00:00 0 
7f2c13e8d000-7f2c13e8f000 r-xp 00000000 fd:00 15678                      /usr/lib64/libdl-2.17.so
7f2c13e8f000-7f2c1408f000 ---p 00002000 fd:00 15678                      /usr/lib64/libdl-2.17.so
7f2c1408f000-7f2c14090000 r--p 00002000 fd:00 15678                      /usr/lib64/libdl-2.17.so
7f2c14090000-7f2c14091000 rw-p 00003000 fd:00 15678                      /usr/lib64/libdl-2.17.so
7f2c14091000-7f2c140b6000 r-xp 00000000 fd:00 16034                      /usr/lib64/libtinfo.so.5.9
7f2c140b6000-7f2c142b6000 ---p 00025000 fd:00 16034                      /usr/lib64/libtinfo.so.5.9
7f2c142b6000-7f2c142ba000 r--p 00025000 fd:00 16034                      /usr/lib64/libtinfo.so.5.9
7f2c142ba000-7f2c142bb000 rw-p 00029000 fd:00 16034                      /usr/lib64/libtinfo.so.5.9
7f2c142bb000-7f2c142dd000 r-xp 00000000 fd:00 612831                     /usr/lib64/ld-2.17.so
7f2c144cf000-7f2c144d3000 rw-p 00000000 00:00 0 
7f2c144d3000-7f2c144d4000 rw-p 00000000 00:00 0 
7f2c144d4000-7f2c144db000 r--s 00000000 fd:00 15997                      /usr/lib64/gconv/gconv-modules.cache
7f2c144db000-7f2c144dc000 rw-p 00000000 00:00 0 
7f2c144dc000-7f2c144dd000 r--p 00021000 fd:00 612831                     /usr/lib64/ld-2.17.so
7f2c144dd000-7f2c144de000 rw-p 00022000 fd:00 612831                     /usr/lib64/ld-2.17.so
7f2c144de000-7f2c144df000 rw-p 00000000 00:00 0 
7ffe6d623000-7ffe6d644000 rw-p 00000000 00:00 0                          [stack]
7ffe6d6d0000-7ffe6d6d2000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

以下区域被标记为代码段(文本段):

00400000-004de000 r-xp:这是/usr/bin/bash可执行文件的代码段,具有可执行和只读权限。

下面的区域被标记为数据段

006dd000-006de000 r--p:这是/usr/bin/bash可执行文件的只读数据段。
006de000-006e7000 rw-p:这是/usr/bin/bash可执行文件的可读写数据段。

共享库和堆栈的内存区域,见maps中的文件名。

基于这个文件计算进程的虚拟内存

import re
import sys

def calculate_virtual_memory(pid):
    virtual_memory_size = 0

    with open(f"/proc/{pid}/maps", "r") as f:
        for line in f:
            match = re.match(r"^([0-9a-fA-F]+)-([0-9a-fA-F]+) .*", line)
            if match:
                start_address = int(match.group(1), 16)
                end_address = int(match.group(2), 16)
                virtual_memory_size += end_address - start_address

    return "{:.3f}".format(virtual_memory_size / 1024 / 1024)

# 用进程的PID调用calculate_virtual_memory函数
pid = int(sys.argv[1])

virtual_memory_size = calculate_virtual_memory(pid)
print(f"Virtual memory size for process {pid}: {virtual_memory_size} MB")

执行脚本,看到与ps -aux看到的虚拟内存相比,多了4K

[root@local-test ~]# python3 sum_virtual_mem.py 20080
Virtual memory size for process 20080: 115684.000 KB

[root@local-test ~]# ps aux | head -1 ; ps aux | grep 20080
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     20080  0.0  0.1 115680  2220 pts/1    Ss   Aug16   0:00 -bash

通过一番比对,在不同进程的maps文件中找到了一样的4K大小的内存地址:

[root@local-test ~]# cat /proc/1044/maps | grep vsyscall
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
[root@local-test ~]# 
[root@local-test ~]# cat /proc/20052/maps | grep vsyscall
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

vsyscall 在每个进程的地址空间中都有一个相同的映射区域,是在内核中实现的,而不是由用户进程加载的共享库。