您当前的位置:首页 > 电脑百科 > 软件技术 > 操作系统 > linux

聊聊 Linux 的内存统计

时间:2020-02-29 11:25:09  来源:  作者:

本文主要分析 linux 系统内存统计的一些指标以及进程角度内存使用监控的一些方法。

开始阅读这篇文章前,请先简单阅读下面的几篇文章。

  • 《进程眼中的线性地址空间》

  • 《线程眼中的线性地址空间》

  • 《聊聊内存管理》

想必这几篇文章过后,基本概念就不需要再赘述了。所以下文直接就找一台 Intel x86_64 架构下安装了 64bit Linux 系统的服务器作为例进行相关的实验和结果分析。Linux 的内存管理从物理内存管理到虚拟内存管理涉及的概念和统计项实在太多,本文从实用和系统运维的角度出发,只列举一些最实用的统计。

 

从 free 命令开始

上面的背景介绍文章把内存相关的基础概念讲的差不多了,这里不再赘述。本文定位是内存统计,所以从最基础的内存统计的命令—free命令开始。执行free命令,可以看到如下的输出:

聊聊 Linux 的内存统计

纵向是内存和Swap分区,横向是统计项。纵向的含义以及Swap不需要解释,我们看横向的统计项:

  • total — 系统总内存(其实就是从 /proc/meminfo获取的)

  • used — 已使用内存

  • free — 未使用的内存

  • shared — 共享内存的大小,主要是 tmpfs

  • buff / cache — bufferscache使用的内存之和

  • available — 可用内存,可以简单理解为未使用的内存和可释放的内存之和(buffer、cache 可以释放大部分,所以这里近似等于 free + buffer / cache 的大小)

这台机器的系统和内核稍微新一点,这个输出可能和你看到的不一样,早先的free命令的输出是这样:

聊聊 Linux 的内存统计

这里的shared为0,因为这台服务器没用共享内存。这里多解释下-/+ buffer/cache这行,字面意思就是used - buffers/cacheused + buffers/cache。前者指的是从应用程序角度系统被用掉了多少内存,后者指的是从应用程序角度看系统还有多少内存能用。听起来很复杂,其实说白了就是因为bufferscached可以被释放出来,多几个指标看看系统还能用多少内存而已。

下面用几个公式来解释这个输出:

1
2
3
4
5
6
7
8
9
10
11
# 内存总量 = 已使用内存 + 空闲内存
`total` = `used` + `free`

# 系统被用掉的内存
`-buffers/cache` = `used` - `buffers` - `cached`

# 系统还能用的内存
`+buffers/cache` = `free` + `buffers` + `cached`

# 所以,其实还有下面的公式
`total` = `-buffers/cache` + `+buffers/cache`

buffers/cached不是100%都能释放出来使用的,上面的“可用内存”其实就是个近似值。最上面新版本系统的输出中有一个available项目表示可用内存,值小于free + buff/cache,内核 3.14 之后支持该特性(虽然也不是绝对意义上的精确的可用内存大小,囧)。

这里稍微多说一点bufferscached。Linux 2.4.10 内核之前,磁盘的缓存有两种,即Buffer CachePage Cache。前者缓存管理磁盘文件系统时读取的块,后者存放访问具体文件内容时生成的页。在 2.4.10 之后,Buffer Cache这个概念就不存在了,这些数据被放在Page Cache中(这种Page被称为Buffer Pages)。

简而言之,现在磁盘的 cache 只有 Page Cache一种,在Page Cache中,有一种PageBuffer Page,这种Page都与一个叫buffer_head的数据结构关联,这些页也就在内存统计中用buffers这个指标来单独统计了。

 

/proc/meminfo 详解

很多命令的内存统计都是从/proc/meminfo读取的。鉴于/proc/meminfo的 man 文档(man proc)写的实在不够清晰,很多条目居然还是To be documented状态,所以这里逐一列举出来常见的统计项解释一下。

首先明确一点,内核目前并没有绝对精确的统计所有的内存使用量,比如alloc_pages接口申请的内存不一定被统计在内(除非所有调用alloc_pages的代码主动进行统计,如果某些不讲究的驱动程序没有主动统计的话统计值就肯定对不上了)。

先看这三项全局统计:

  • MemTotal — 总的全局可用内存大小(即物理RAM减去保留的以及内核代码占用的,系统启动后一般固定不变)

  • MemFree — 总的全局未使用内存大小

  • MemAvailable — 内核估计出来的全局可用内存大小,非精确值(MemFree不代表所有可用的内存,Cache/BufferSlab均有部分可以临时释放的内存要计算在内)

用户进程的内存页分为两种:

  1. 与文件关联的内存页(File-backed Pages), 比如程序文件、读取文件时数据对应的缓存页

  2. 与文件无关的匿名内存页(Anonymous Pages),比如进程的堆、栈等分配的内存

所有Page Cache里的页面都是File-backed PagesFile-backed Pages在内存不足的时候可以直接写回对应的硬盘文件里,即Page-out。而Anonymous Pages在内存不足时就只能写到硬盘上的交换区Swap里来释放内存,称之为Swap-out

Anonymous Pages与用户进程共存,进程退出则Anonymous pages释放,而Page Cache即使在进程退出后还可以缓存。

下面是磁盘缓存相关的统计项:

  • Buffers — 块设备所占用的缓存页,比如磁盘文件系统的meta信息如SuperBlock等,直接读写块设备产生的缓存也统计在这里(例如dd命令)

  • Cached — 从磁盘读取的文件内容缓存(即Page cache

  • SwapCached — Swap中包含的确定要被换出,但是尚未写入物理交换区的匿名内存页

  • SwapTotal — 可用的磁盘Swap总大小

  • SwapFree — 磁盘Swapfree大小

  • Dirty — 修改了等待写回磁盘的内存大小

  • Writeback — 正在写回磁盘的内存大小

以下几项和内核的页面回收算法(Page Frame Reclaiming)相关,Page Cache和所有用户进程的内存(除内核栈和HugePages外)都在相关的LRU Lists上。内核在 2.6 以前就引入了增强的LRU算法来解决朴素的LRU算法完全不考虑使用频率的问题。具体的Active 链表Inactive 链表的使用详情请参阅其他资料。

  • Active — 最近使用的内存,回收的优先级低

  • Inactive — 最近较少使用的内存,回收的优先级高

  • Active (anon) — Active 链表中的匿名页(Anonymous Pages)部分

  • Inactive (anon) — Inactive 链表中的匿名页(Anonymous Pages)部分

  • Active (file) — Active 链表中的File-backed Pages部分

  • Inactive (file) — Inactive 链表中的File-backed Pages部分

  • Unevictable — 禁止换出的页,对应Unevictable 链表,其中包括VM_LOCKED的内存页、SHM_LOCK的共享内存页(也统计在Mlocked中)、和Ramfs

  • Mlocked — mlock系统调用锁定的内存大小

共享内存在 Linux 中细分的话可以分为以下几种:

  • SystemV Shared Memory — shmget

  • POSIX Shared Memory — shm_open

  • Shared Anonymous Memory — mmap(MAP_ANONYMOUS | MAP_SHARED)

共享内存在内核中都是 基于tmpf机制实现 的。因为基于文件系统所以就不能算是匿名页,不能计入AnonPages的统计项,而只能计入CachedMApped统计项。但是,tmpfs背后并没有真实的磁盘文件存在,如果想要被临时释放出来,只能通过Swap的方式,所以内存页被链接到了Inactive(anon)Active(anon)里。

也就是说,共享内存的页面属于File-backed Pages,但是被放在Inactive(anon)Active(anon)链表里,统计也不算在AnonPages里,而是算在CachedMapped里。特别地,如果这些页被mlock的话,就放在Unevictable链里并计算在内。所以从数值上看,Inactive(anon)项 +Active(anon)项 不等于AnonPages项,因为前者包括共享内存的部分。Active(file)项 +Inactive(file)项 也不等于Mapped项,因为前者中包括Unmapped的内存,后者还包含共享内存的部分(这部分在Inactive(anon)Active(anon)里)。

这里有一个情况要注意,与文件关联的页也有可能是匿名页(MAP_PRIVATE映射的页面被修改时会产生一个匿名页拷贝),会被算到AnonPages里。

与此相关的相关的统计项有:

  • AnonPages — 匿名页(Anonymous pages)的大小,同时也包含Transparent HugePages (THP)对应的 AnonHugePages

  • Mapped — 设备和文件等映射的大小,Mapped统计了Cached中所有的Mapped页面,是Cached的子集(满足Cached-Mapped=Unmapped)。共享内存、可执行程序的文件、动态库、mmap的文件等都统计在这里

  • Shmem — 共享内存的大小,包括Shared Memorytmpfsdevtmpfs

注意 Linux 的内存是真正使用时才分配的,所以注意这里的大小都是已分配的大小,而不是程序里申请的大小。

下面都是内核使用的内存相关的统计项:

  • Slab — 内核Slab结构使用的大小(就是那个Slab分配器占用的)

  • SReclaimable — 内核Slab里面可回收的部分(调用kmem_getpages()时带有 SLAB_RECLAIM_ACCOUNT 标的)

  • SUnreclaim — Slab里面无法回收的大小,等于Slab项 -SReclaimable

  • KernelStack — 分配给内核栈的大小(每个用户线程都会分配一个Kernel Stack,系统调用syscalltrapexception后进入内核态执行代码时候使用)

  • PageTables — 页表的大小(就是经常挂在嘴上的那个页表)

  • NFS_Unstable — 发送到服务端但尚未提交的 NFS 页的大小

  • Bounce — 块设备 “bounce buffers” 部分的大小(有些老设备只能访问低端内存,比如 16M 以下,这部分分配的 buffer 统计在这里)

  • WritebackTmp — FUSE 用于写回磁盘的缓冲区的大小

  • VmallocTotal — vmalloc 区域大小

  • VmallocUsed — vmalloc 区域使用大小

  • VmallocChunk — vmalloc 区域最大的 free 连续区块大小

  • HardwareCorrupted — 系统检测到内存的硬件故障的内存大小(问题页会被记录不再使用)

之前说过,HugePages 是独立统计的,如果进程使用了 HugePages,是不会计入自身的RSS/PSS的。注意下面的AnonHugePages指的是透明大页(THP,Transparent HugePages),THP是统计在进程的RSS/PSS里的,要注意区别。下面是相关的统计项:

  • AnonHugePages — 透明大页 THP 使用的大小

  • HugePages_Total — 内存大页的总量,对应 /proc/sys/vm/nr_hugepages,可以动态改

  • HugePages_Free — 内存大页中 free 的大小

  • HugePages_Rsvd — 内存大页中能分配出来的大小

  • HugePages_Surp — 内存大页中超过 /proc/sys/vm/nr_hugepages的大小, 最大值由/proc/sys/vm/nr_overcommit_hugepages限制

  • Hugepagesize — 内存大页的页大小

 

进程级别的统计

先介绍几个通用概念:

  • VSS - Virtual Set Size,虚拟内存大小,包含共享库占用的全部内存,以及分配但未使用内存

  • RSS - Resident Set Size,实际使用物理内存,包含了共享库占用的全部内存

  • PSS - Proportional Set Size,实际使用的物理内存,共享库占用的内存按照进程数等比例划分

  • USS - Unique Set Size,进程独自占用的物理内存,不包含共享库占用的内存

 

/proc/{pid}/smaps 文件

/proc/{pid}/smaps文件对应每个进程的详细内存分段统计。截取一部分:

聊聊 Linux 的内存统计

下面分别解释下含义:

  • Size:映射的大小(mapping size

  • Rss:实际驻留在RAM的内存大小(包括共享库的大小,不包括已经交换出去的页面)

  • Pss:Rss 的基础上,把共享库的大小均摊给所有被映射的进程后的大小

  • Shared_Clean:共享的Clean内存的大小

  • Shared_Dirty:共享的Dirty内存的大小

  • Private_Clean:私有的Clean内存的大小

  • Private_Dirty:私有的Dirty内存的大小

  • Referenced:当前被标记为引用的页的大小

  • Anonymous:匿名内存的大小

  • AnonHugePages:透明大页内存的大小

  • Swap:Swap的大小

  • KernelPageSize:内核页大小

  • MMUPageSize:MMU页大小

  • Locked:被mlock的内存大小

  • VmFlags:页的标志位,有点多这里不列举,详见参考资料 [4]

可以看到Rss这个指标实际上是包含了共享库的大小的,不同的进程会共享这个映射的,如果想通过累加这个值来计算所有进程用到的内存的话就不准确了,而Pss把共享库的大小均摊给了所有用到映射了这个库的进程,所以累加起来就不会重复计算共享库大小了。

P.S. 最新的内核文档提到了要加smaps_rollup这个统计,支持Pss_AnonPss_FilePss_Shmem三个分类统计,这个在进程级别看,用到内存就很清晰了。

我们可以累加一下这个值看看某进程用到的内存总和:

聊聊 Linux 的内存统计

注意单位是KB,所以这里进程用到的内存是 1.17 GB 左右。

这是个使用共享内存作为存储的服务,所以这是符合预期的。如果想要看排除共享内存的部分,那要看Anonymous部分的总和:

聊聊 Linux 的内存统计

所以实际匿名内存使用是 63 MB 左右。

 

top 命令

top命令中关于内存使用的统计:

聊聊 Linux 的内存统计

内存相关的统计有VIRTRESSHRSWAPCODEDATAUSED

  • VIRT — Virtual Memory Size,虚拟内存大小,包括所有代码、数据和共享库,以及已交换的页面和已映射但未使用的内存

  • RES — Resident Memory Size,驻留内存大小,共享的内存比如动态库也会计算在内

  • SHR — Shared Memory Size,共享的内存大小,并非所有共享的内存都是常驻的

  • SWAP — Swapped Size,非驻留内存大小

  • CODE — Code Size,程序可执行代码的大小

  • DATA — Data + Stack Size,可执行代码以外的物理内存量,也称为数据驻留集大小

  • USED — Memory in Use,RES + SWAP 的大小

 

其他的内存查看命令

常用的还有这些:vmstatsarslabtopkmstatpsprstatpmap等等。懒得写了,有问题看man文档得了。

 

参考文献

[1] Understanding the Linux Kernel, Daniel Plerre Bovet / Marco Cesati, 2005-11

[2] Professional Linux Kernel Architecture, Wolfgang Mauerer, 2008-10-13

[3] Systems Performance: Enterprise and the Cloud, Brendan Gregg, 2013-10-26

[4] https://raw.githubusercontent.com/torvalds/linux/master/Documentation/filesystems/proc.txt

[5] https://en.wikipedia.org/wiki/Resident_set_size

[6] https://en.wikipedia.org/wiki/Proportional_set_size

[7] https://en.wikipedia.org/wiki/Unique_set_size



Tags:Linux 内存   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
对于精通 CURD 的业务同学,内存管理好像离我们很远,但这个知识点虽然冷门(估计很多人学完根本就没机会用上)但绝对是基础中的基础。这就像武侠小说中的内功修炼,学完之后看不到立...【详细内容】
2020-12-09  Tags: Linux 内存  点击:(191)  评论:(0)  加入收藏
本文主要分析 Linux 系统内存统计的一些指标以及进程角度内存使用监控的一些方法。开始阅读这篇文章前,请先简单阅读下面的几篇文章。 《进程眼中的线性地址空间》 《线程...【详细内容】
2020-02-29  Tags: Linux 内存  点击:(93)  评论:(0)  加入收藏
导语本文将介绍几种内存泄漏检测工具,并通过实际例子介绍一种分析堆内存占用量的工具和方法,帮助定位内存膨胀问题。背景进程的内存管理是每一个开发者必须要考虑的问题,对于C+...【详细内容】
2019-12-11  Tags: Linux 内存  点击:(176)  评论:(0)  加入收藏
很多次,你可能遇见过系统消耗了过多的内存。如果是这种情况,那么最好的办法是识别出 Linux 机器上消耗过多内存的进程。-- Magesh Maruthamuthu(作者)很多次,你可能遇见过系统消...【详细内容】
2019-11-20  Tags: Linux 内存  点击:(111)  评论:(0)  加入收藏
上一篇我们了解了内存在内核态是如何管理的,本篇文章我们一起来看下内存在用户态的使用情况,如果上一篇文章说是内核驱动工程师经常面对的内存管理问题,那本篇就是应用工程师常...【详细内容】
2019-09-27  Tags: Linux 内存  点击:(145)  评论:(0)  加入收藏
这篇博客主要介绍 linux 环境下,查看内存占用的两种方式:使用 ps,top等命令;查看/proc/[pid]/下的文件。文章简要介绍了命令的使用方法与一些参数意义,同时对/proc/[pid]/下的...【详细内容】
2019-08-29  Tags: Linux 内存  点击:(339)  评论:(0)  加入收藏
▌简易百科推荐
作用显示文件或目录所占用的磁盘空间使用命令格式du [option] 文件/目录命令功能显示文件或目录所占用的磁盘空间一些写法的区别du -sh xxx 显示总目录的大小,但是不会列出...【详细内容】
2021-12-23  mitsuhide1992    Tags:du命令   点击:(12)  评论:(0)  加入收藏
什么是linux内核linux就像是一个哲学的最佳实践。如果非要对它评价,我真的不知道该怎么赞叹,我只能自豪地说着:“linux的美丽简直让人沉醉。”我只能说是我处在linux学习的修炼...【详细内容】
2021-12-23  linux上的码农    Tags:linux内核   点击:(15)  评论:(0)  加入收藏
本文将比较 Linux 中 service 和 systemctl 命令,先分别简单介绍这两个命令的基础用法,然后进行比较。从 CentOS 7.x 开始,CentOS 开始使用 systemd 服务来代替 service服务(dae...【详细内容】
2021-12-23  软件架构    Tags:systemctl   点击:(14)  评论:(0)  加入收藏
mv是move的缩写,可以用来移动文件或者重命名文件名,经常用来备份文件或者目录。命令格式mv [选项] 源文件或者目录 目标文件或者目录命令功能mv命令中第二个参数类型的不同(...【详细内容】
2021-12-17  入门小站    Tags:mv命令   点击:(23)  评论:(0)  加入收藏
大数据技术AI Flink/Spark/Hadoop/数仓,数据分析、面试,源码解读等干货学习资料 98篇原创内容 -->公众号 Linux sed 命令是利用脚本来处理文本文件。sed 可依照脚本的指令来处...【详细内容】
2021-12-17  仙风道骨的宝石骑士    Tags:sed命令   点击:(22)  评论:(0)  加入收藏
Node是个啥?  写个东西还是尽量面面俱到吧,所以有关基本概念的东西我也从网上选择性地拿了下来,有些地方针对自己的理解有所改动,对这些概念性的东西有过了解的可选择跳过这段...【详细内容】
2021-12-15  linux上的码农    Tags:node   点击:(25)  评论:(0)  加入收藏
难道只有我一个人觉得Ubuntu的unity桌面非常好用吗?最近把台式机上面的Ubuntu 16.04格式化了,装了黑苹果用了一周,不得不说,MacOS确实很精美,软件生态比Linux丰富很多,比Windows简...【详细内容】
2021-12-14  地球末日村    Tags:ubuntu   点击:(40)  评论:(0)  加入收藏
简介Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Memberships) 等等。输出信息含义执行net...【详细内容】
2021-12-13  窥镜天    Tags:Linux netstat   点击:(28)  评论:(0)  加入收藏
对于较多数量的文件描述符的监听无论是select还是poll系统调用都显得捉襟见肘,poll每次都需要将所有的文件描述符复制到内核,内核本身不会对这些文件描述符加以保存,这样的设计...【详细内容】
2021-12-13  深度Linux    Tags:Linux   点击:(19)  评论:(0)  加入收藏
今天,我们来了解下 Linux 系统的革命性通用执行引擎-eBPF,之所以聊着玩意,因为它确实牛逼,作为一项底层技术,在现在的云原生生态领域中起着举足轻重的作用。截至目前,业界使用范...【详细内容】
2021-12-10  架构驿站    Tags:eBPF   点击:(29)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条