在top命令的结果中,有一个VIRT 的输出项,这个项的官方解释如下:
代码语言:javascript复制VIRT -- Virtual Memory Size (KiB)
The total amount of virtual memory used by the task. It includes all code, data and shared libraries plus pages that have been
swapped out and pages that have been mapped but not used.
从字面理解,就是一个task占用的虚拟内存的大小,包括代码,数据,共享库,swap out的pages,以及mapped 了但是还没有used 的pages. 而我们已经知道,这里page的概念其实是内存的“页”,内存采用分页机制;所以,简单来说,VIRT就是代码,数据,共享库以及map为内存可以访问的其他数据,无论这些数据是在物理内存还是在虚拟内存,只要是已经Map为内存可以访问的,那么都算数. 那具体来说,上述的数据都map了哪些文件,哪些内存地址呢? 其实可以在 proc 中找出的;
先说结论,然后做个简单的验证:
VIRT的大小,等于/proc/maps的大小的综合,而map对应的文件的大小,可以通过 /proc/map_files进行计算,这个值和maps 中的文件相关项计算出来的大小是一致的,而剩下的非文件相关的则是: heap, stack ...,也就是说VIRT的大小,其实就是已经map的文件的大小加上堆,栈, 以及其他的空间等;而其他空间则主要是堆空间的大小,另外还有栈空间... 验证过程如下:
- 在/proc/{PID}/maps 下面,就表示当前的task已经进了map的地址空间,我们可以验证下这些空间总的大小,默认是KB,方法如下:
root:8094# head maps #我们看这个文件的前10行内容,其中第一列就是map的内存地址空间;
55f319b10000-55f319dc8000 r-xp 00000000 fd:02 403346422 /usr/bin/vim
55f319fc7000-55f319fd6000 r--p 002b7000 fd:02 403346422 /usr/bin/vim
55f319fd6000-55f319ff0000 rw-p 002c6000 fd:02 403346422 /usr/bin/vim
55f319ff0000-55f31a000000 rw-p 00000000 00:00 0
55f31b7f6000-55f31bb35000 rw-p 00000000 00:00 0 [heap]
7fbf0b2fa000-7fbf0b305000 r-xp 00000000 fd:02 960898 /usr/lib64/libnss_files-2.28.so
7fbf0b305000-7fbf0b505000 ---p 0000b000 fd:02 960898 /usr/lib64/libnss_files-2.28.so
7fbf0b505000-7fbf0b506000 r--p 0000b000 fd:02 960898 /usr/lib64/libnss_files-2.28.so
7fbf0b506000-7fbf0b507000 rw-p 0000c000 fd:02 960898 /usr/lib64/libnss_files-2.28.so
7fbf0b507000-7fbf0b50d000 rw-p 00000000 00:00 0
root:8094# cat maps | awk '{print $1}' | awk -F'[-]' '{s=strtonum("0x"$1);e=strtonum("0x"$2);sum =e-s}END{print sum/1024}' #计算maps下总的已经map的大小;单位是KB.
257600
- 看下top 下该进程占用的空间大小:
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 6.8 us, 3.2 sy, 0.0 ni, 88.7 id, 0.0 wa, 0.8 hi, 0.5 si, 0.0 st
MiB Mem : 7704.4 total, 2043.3 free, 2798.0 used, 2863.1 buff/cache
MiB Swap: 7708.0 total, 7708.0 free, 0.0 used. 4025.6 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND
8094 root 20 0 257596 9128 5508 S 0.0 0.1 0:00.06 vim
- 对于两者之间的差距,top 显示VIRT是257596, 而 cat /proc/8094/maps ,然后计算得到的结果是257600, 刚好相差一个4KB,这个是一个PAGE, 出现这个的原因是page 对齐导致的;在实际的map过程中,因为对齐的原因,所以占用的实际空间多了一个PAGE, 在这个例子中是一个PAGE, 不一定在其他的例子中也是一个PAGE,但是应该都是4KB的整数倍;
- 计算/proc/{PID}/file_maps下map的空间大小,可以发现这个大小和 maps下的文件相关的大小是一致的;
- 堆空间不一定是连续的,而栈空间则是连续的;堆空间依靠函数调用来申请,而栈空间则系统自动管理;用户程序代码申请的空间一般都是堆空间;
上述的/proc/maps 描述了map的大致情形,但是对于每一个不同的map, 内存是如何分配的呢? 这时候可以通过/proc/{PID}/smaps来获得;