Linux 内核把物理内存分为了两部分:
一部分是映射至文件的(有文件背景的),一部分是没有映射至文件的,即匿名内存,它们和共不共享没有关系!
什么是匿名内存?匿名内存就是没有文件背景的内存,就是无法和磁盘进行交换的,比如堆栈。
进程通过如下方式占用的物理内存,计入 file_rss,也就是 top 的 SHR 字段。
- 程序的代码段。
- 动态库的代码段。
- 通过 mmap 做的文件映射。
- 通过 mmap 做的匿名映射,但指明了MAP_SHARED属性。
- 通过 shmget 申请的共享内存。
我们看到一般这些内存都是以共享方式存在。
下面是 top 命令的输出片断:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4982 oracle 20 0 837932 115328 113312 S 0.0 6.2 0:01.09 oracle
top 命令通过解析 /proc/<pid>/statm 统计 VIRT、RES 和 SHR 字段值:
# cat /proc/4982/statm
209483 28832 28328 47296 0 965 0
209483*4=837932,即 VIRT,进程虚存的总大小,即进程申请的内存大小。
28832*4=115328,即 RES,即平常我们说的常驻内存,是进程真正使用的内存量。
28328*4=113312,即 SHR,即平常我们说的共享内存,上面已经描述过哪些内存会被计入共享内存。
新 fork 之后的子进程,由于 copy on write 机制,在页面被修改之前,和父进程共享。这部分值并不体现在 top 命令的 SHR 字段内。
所以 top 命令的 SHR 并不是准确描述了进程与其他进程共享使用的内存数量,是存在误差的。
如何获取准确获取进程的共享内存量和独占内存量呢?
共享内存量:
# grep Shared_ /proc/4982/smaps | awk 'BEGIN {sum=0} {sum+=$2} END {print sum}'
61360
独占内存量:
# grep Private_ /proc/4982/smaps | awk 'BEGIN {sum=0} {sum+=$2} END {print sum}'
54096
这两个值加起来为 115456,跟上面的 RES 大致相当。