前言
想必在 linux 上写过程序的同学都有剖析过程占用多少内存的经验,或者被问到这样的问题——你的程序在运行时占用了多少内存(物理内存)?
通常咱们能够通过 top 命令查看过程占用了多少内存。这里咱们能够看到 VIRT、RES 和 SHR 三个重要的指标,他们别离代表什么意思呢?
这是本文须要跟大家一起探讨的问题。当然如果更加深刻一点,你可能会问过程所占用的那些物理内存都用在了哪些地方?这时候 top 命令可能不能给到你你所想要的答案了,不过咱们能够剖析 proc 文件系统提供的 smaps 文件,这篇文章详尽地列出了以后过程所占用物理内存的应用状况。
本文将分为三个局部:
1、简要论述虚拟内存和驻留内存这两个重要的概念;
2、解释 top 命令中 VIRT、RES 以及 SHR 三个参数的理论参考意义;
3、向大家介绍一下 smaps 文件的格局,通过剖析 smaps 文件咱们能够具体理解过程物理内存的应用状况,比方 mmap 文件占用了多少空间、动态内存开拓耗费了多少空间、函数调用栈耗费了多少空间等等。
一、对于内存的两个概念
要了解 top 命令对于内存应用状况的输入,咱们必须首先搞清楚虚拟内存(Virtual Memory)和驻留内存(Resident Memory)两个概念。
(1)虚拟内存
首先须要强调的是虚拟内存不同于物理内存,尽管两者都蕴含内存字眼然而它们属于两个不同层面的概念。过程占用虚拟内存空间大并非意味着程序的物理内存也肯定占用很大。虚拟内存是操作系统内核为了对过程地址空间进行治理(process address space management)而精心设计的一个逻辑意义上的内存空间概念。
咱们程序中的指针其实都是这个虚拟内存空间中的地址。比方咱们在写完一段 C ++ 程序之后都须要采纳 g ++ 进行编译,这时候编译器采纳的地址其实就是虚拟内存空间的地址。因为这时候程序还没有运行,何谈物理内存空间地址?但凡程序运行过程中可能须要用到的指令或者数据都必须在虚拟内存空间中。
既然说虚拟内存是一个逻辑意义上(假象的)的内存空间,为了可能让程序在物理机器上运行,那么必须有一套机制能够让这些假象的虚拟内存空间映射到物理内存空间(实实在在的 RAM 内存条上的空间)。这其实就是操作系统中页映射表(page table)所做的事件了。
内核会为零碎中每一个过程保护一份互相独立的页映射表。页映射表的基本原理是将程序运行过程中须要拜访的一段虚拟内存空间通过页映射表映射到一段物理内存空间上,这样 CPU 拜访对应虚拟内存地址的时候就能够通过这种查找页映射表的机制拜访物理内存上的某个对应的地址。“页(page)”是虚拟内存空间向物理内存空间映射的根本单元。
下图演示了虚拟内存空间和物理内存空间的互相关系,它们通过 Page Table 关联起来。其中虚拟内存空间中着色的局部别离被映射到物理内存空间对应雷同着色的局部。而虚拟内存空间中灰色的局部示意在物理内存空间中没有与之对应的局部,也就是说灰色局部没有被映射到物理内存空间中。这么做也是本着“按需映射”的指导思想,因为虚拟内存空间很大,可能其中很多局部在一次程序运行过程中基本不须要拜访,所以也就没有必要将虚拟内存空间中的这些局部映射到物理内存空间上。
到这里为止曾经根本论述了什么是虚拟内存了。
总结一下就是,虚拟内存是一个假象的内存空间,在程序运行过程中虚拟内存空间中须要被拜访的局部会被映射到物理内存空间中。虚拟内存空间大只能示意程序运行过程中可拜访的空间比拟大,不代表物理内存空间占用也大。
(2)驻留内存
驻留内存,顾名思义是指那些被映射到过程虚拟内存空间的物理内存。上图中,在零碎物理内存空间中被着色的局部都是驻留内存。比方,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 蕴含了在曾经映射到物理内存空间的局部和尚未映射到物理内存空间的局部总和。
RES 的含意是指过程虚拟内存空间中曾经映射到物理内存空间的那局部的大小。对应到图 1 中的过程 A 来说就是 A1、A2、A3 以及 A4 几个局部空间的总和。所以说,看过程在运行过程中占用了多少内存应该看 RES 的值而不是 VIRT 的值。
最初来看看 SHR 所示意的含意。
SHR 是 share(共享)的缩写,它示意的是过程占用的共享内存大小。在上图中咱们看到过程 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 文件中,每一条记录(如下图所示)示意过程虚拟内存空间中一块间断的区域。其中第一行从左到右顺次示意地址范畴、权限标识、映射文件偏移、设施号、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。
有了 smap 如此具体对于虚拟内存空间到物理内存空间的映射信息,置信大家曾经可能通过剖析该文件答复下面提出的 4 个问题。
最初心愿大家可能通过浏览本文对过程的虚拟内存和物理内存有一个更加清晰意识,并能更加精确了解 top 命令对于内存的输入,最初能够通过 smaps 文件更进一步剖析过程应用内存的状况。
————————————————
版权申明:本文为 CSDN 博主「京东云开发者」的原创文章,遵循 CC 4.0 BY-SA 版权协定,转载请附上原文出处链接及本申明。
原文链接:https://blog.csdn.net/jdcdev_…