理解virt res shr之间的关系

想必在linux上写过程序的同学都有分析进程占用多少内存的经历 , 或者被问到这样的问题—— 你的程序在运行时占用了多少内存(物理内存) ?通常我们可以通过top命令查看进程占用了多少内存 。 这里我们可以看到VIRT、RES和SHR三个重要的指标 , 他们分别代表什么意思呢?这是本文需要跟大家一起探讨的问题 。 当然如果更加深入一点 , 你可能会问进程所占用的那些物理内存都用在了哪些地方?这时候top命令可能不能给到你你所想要的答案了 , 不过我们可以分析proc文件系统提供的smaps文件 , 这个文件详尽地列出了当前进程所占用物理内存的使用情况 。
本文将分为三个部分 。 第一部分简要阐述虚拟内存和驻留内存这两个重要的概念;
第二部分解释top命令中VIRT、RES以及SHR三个参数的实际参考意义;
最后一部分向大家介绍一下smaps文件的格式 , 通过分析smaps文件我们可以详细了解进程物理内存的使用情况 , 比如mmap文件占用了多少空间、动态内存开辟消耗了多少空间、函数调用栈消耗了多少空间等等 。
关于内存的两个概念要理解top命令关于内存使用情况的输出 , 我们必须首先搞清楚虚拟内存(Virtual Memory)和驻留内存(Resident Memory)两个概念 。
虚拟内存首先需要强调的是虚拟内存不同于物理内存 , 虽然两者都包含内存字眼但是它们属于两个不同层面的概念 。 进程占用虚拟内存空间大并非意味着程序的物理内存也一定占用很大 。 虚拟内存是操作系统内核为了对进程地址空间进行管理(process address space management)而精心设计的一个逻辑意义上的内存空间概念 。 我们程序中的指针其实都是这个虚拟内存空间中的地址 。 比如我们在写完一段C++程序之后都需要采用g++进行编译 , 这时候编译器采用的地址其实就是虚拟内存空间的地址 。 因为这时候程序还没有运行 , 何谈物理内存空间地址?凡是程序运行过程中可能需要用到的指令或者数据都必须在虚拟内存空间中 。 既然说虚拟内存是一个逻辑意义上(假象的)的内存空间 , 为了能够让程序在物理机器上运行 , 那么必须有一套机制可以让这些假象的虚拟内存空间映射到物理内存空间(实实在在的RAM内存条上的空间) 。 这其实就是操作系统中页映射表(page table)所做的事情了 。 内核会为系统中每一个进程维护一份相互独立的页映射表 。。 页映射表的基本原理是将程序运行过程中需要访问的一段虚拟内存空间通过页映射表映射到一段物理内存空间上 , 这样CPU访问对应虚拟内存地址的时候就可以通过这种查找页映射表的机制访问物理内存上的某个对应的地址 。 “页(page)”是虚拟内存空间向物理内存空间映射的基本单元 。
下图1演示了虚拟内存空间和物理内存空间的相互关系 , 它们通过Page Table关联起来 。 其中虚拟内存空间中着色的部分分别被映射到物理内存空间对应相同着色的部分 。 而虚拟内存空间中灰色的部分表示在物理内存空间中没有与之对应的部分 , 也就是说灰色部分没有被映射到物理内存空间中 。 这么做也是本着“按需映射”的指导思想 , 因为虚拟内存空间很大 , 可能其中很多部分在一次程序运行过程中根本不需要访问 , 所以也就没有必要将虚拟内存空间中的这些部分映射到物理内存空间上 。
到这里为止已经基本阐述了什么是虚拟内存了 。 总结一下就是 , 虚拟内存是一个假象的内存空间 , 在程序运行过程中虚拟内存空间中需要被访问的部分会被映射到物理内存空间中 。 虚拟内存空间大只能表示程序运行过程中可访问的空间比较大 , 不代表物理内存空间占用也大 。
理解virt res shr之间的关系文章插图
图1. 虚拟内存空间到物理内存空间映射
驻留内存驻留内存 , 顾名思义是指那些被映射到进程虚拟内存空间的物理内存 。 上图1中 , 在系统物理内存空间中被着色的部分都是驻留内存 。 比如 , A1、A2、A3和A4是进程A的驻留内存;B1、B2和B3是进程B的驻留内存 。 进程的驻留内存就是进程实实在在占用的物理内存 。 一般我们所讲的进程占用了多少内存 , 其实就是说的占用了多少驻留内存而不是多少虚拟内存 。 因为虚拟内存大并不意味着占用的物理内存大 。
关于虚拟内存和驻留内存这两个概念我们说到这里 。 下面一部分我们来看看top命令中VIRT、RES和SHR分别代表什么意思 。
top命令中VIRT、RES和SHR的含义
搞清楚了虚拟内存的概念之后解释VIRT的含义就很简单了 。 VIRT表示的是进程虚拟内存空间大小 。 对应到图1中的进程A来说就是A1、A2、A3、A4以及灰色部分所有空间的总和 。 也就是说VIRT包含了在已经映射到物理内存空间的部分和尚未映射到物理内存空间的部分总和 。