理解virt res shr之间的关系( 二 )


RES的含义是指进程虚拟内存空间中已经映射到物理内存空间的那部分的大小 。 对应到图1中的进程A来说就是A1、A2、A3以及A4几个部分空间的总和 。 所以说 , 看进程在运行过程中占用了多少内存应该看RES的值而不是VIRT的值 。
最后来看看SHR所表示的含义 。 SHR是share(共享)的缩写 , 它表示的是进程占用的共享内存大小 。 在上图1中我们看到进程A虚拟内存空间中的A4和进程B虚拟内存空间中的B3都映射到了物理内存空间的A4/B3部分 。 咋一看很奇怪 。 为什么会出现这样的情况呢?其实我们写的程序会依赖于很多外部的动态库(.so) , 比如libc.so、libld.so等等 。 这些动态库在内存中仅仅会保存/映射一份 , 如果某个进程运行时需要这个动态库 , 那么动态加载器会将这块内存映射到对应进程的虚拟内存空间中 。 多个进展之间通过共享内存的方式相互通信也会出现这样的情况 。 这么一来 , 就会出现不同进程的虚拟内存空间会映射到相同的物理内存空间 。 这部分物理内存空间其实是被多个进程所共享的 , 所以我们将他们称为共享内存 , 用SHR来表示 。 某个进程占用的内存除了和别的进程共享的内存之外就是自己的独占内存了 。 所以要计算进程独占内存的大小只要用RES的值减去SHR值即可 。
进程的smaps文件
通过top命令我们已经能看出进程的虚拟空间大小(VIRT)、占用的物理内存(RES)以及和其他进程共享的内存(SHR) 。 但是仅此而已 , 如果我想知道如下问题:
进程的虚拟内存空间的分布情况 , 比如heap占用了多少空间、文件映射(mmap)占用了多少空间、stack占用了多少空间?
进程是否有被交换到swap空间的内存 , 如果有 , 被交换出去的大小?
mmap方式打开的数据文件有多少页在内存中是脏页(dirty page)没有被写回到磁盘的?
mmap方式打开的数据文件当前有多少页面已经在内存中 , 有多少页面还在磁盘中没有加载到page cahe中?
等等
以上这些问题都无法通过top命令给出答案 , 但是有时候这些问题正是我们在对程序进行性能瓶颈分析和优化时所需要回答的问题 。 所幸的是 , 世界上解决问题的方法总比问题本身要多得多 。 linux通过proc文件系统为每个进程都提供了一个smaps文件 , 通过分析该文件我们就可以一一回答以上提出的问题 。
在smaps文件中 , 每一条记录(如下图2所示)表示进程虚拟内存空间中一块连续的区域 。 其中第一行从左到右依次表示地址范围、权限标识、映射文件偏移、设备号、inode、文件路径 。 详细解释可以参见understanding-linux-proc-id-maps 。
接下来8个字段的含义分别如下:

  • Size:表示该映射区域在虚拟内存空间中的大小 。
  • Rss:表示该映射区域当前在物理内存中占用了多少空间
  • Shared_Clean:和其他进程共享的未被改写的page的大小
  • Shared_Dirty: 和其他进程共享的被改写的page的大小
  • Private_Clean:未被改写的私有页面的大小 。
  • Private_Dirty: 已被改写的私有页面的大小 。
  • Swap:表示非mmap内存(也叫anonymous memory , 比如malloc动态分配出来的内存)由于物理内存不足被swap到交换空间的大小 。
  • Pss:该虚拟内存区域平摊计算后使用的物理内存大小(有些内存会和其他进程共享 , 例如mmap进来的) 。 比如该区域所映射的物理内存部分同时也被另一个进程映射了 , 且该部分物理内存的大小为1000KB , 那么该进程分摊其中一半的内存 , 即Pss=500KB 。

理解virt res shr之间的关系文章插图
图2. smaps文件中的一条记录
有了smap如此详细关于虚拟内存空间到物理内存空间的映射信息 , 相信大家已经能够通过分析该文件回答上面提出的4个问题 。
【理解virt res shr之间的关系】最后希望所有读者能够通过阅读本文对进程的虚拟内存和物理内存有一个更加清晰认识 , 并能更加准确理解top命令关于内存的输出 , 最后可以通过smaps文件更进一步分析进程使用内存的情况 。