最近在维护一台CentOS服务器的时候,发现内存无故"损失"了许多,free和ps统计的结果相差十几个G,搞的我一度又觉得遇到灵异事件了,后来Google了许久才搞明白,特此记录一下,以供往后查询。php
虽然每天都在用Linux系统办公,其实对它的了解也不过尔尔。毕业几年才迈入"知道本身不知道"的境界,我以为本身丝毫没有愧对万年吊车尾这个称号 :(html
同事说有一台服务器的内存用光了,我连上去用free看了下,确实有点怪。node
$ free -g total used free shared buffers cached Mem: 15 15 0 0 2 0 -/+ buffers/cache: 12 2 Swap: 17 0 17
这台服务器有16G内存,可是结果显示除了2G左右的文件Buffer缓存外,其他十几G都被确确实实的用光了。(free按1024进制计算,总内存可能比实际偏小)linux
这里大概介绍下free结果的含义:缓存
/ | total | used | free | shared | buffers | cached |
---|---|---|---|---|---|---|
Mem | 总物理内存 | 当前使用的内存(包括slab+buffers+cached) | 彻底没有使用的内存 | 进程间共享的内存 | 缓存文件的元数据1 | 缓存文件的具体内容1 |
-/+ buffers/cache | 当前使用的内存(不包括buffers+cached,但包括slab) | 未使用和缓存的内存(free+buffers+cached) | ||||
Swap | 总的交换空间 | 已使用的交换空间 | 未使用的交换空间 |
而后top看了下,没有特别吃内存的程序。用ps大概统计下全部程序占用的总内存:服务器
$ ps aux | awk '{mem += $6} END {print mem/1024/1024}' 0.595089
结果显示全部进程占用的内存还不到1G,实际上,由于free, ps的统计方式的差异和Copy-on-write和Shared libraries等内存优化机制的存在,这二者的统计结果一般是不同的。可是通常状况下绝对不会相差十几个G,确定是有什么隐藏的问题,Google了许久后发现,free没有专门统计另外一项缓存: Slab。app
Slab Allocation是Linux 2.2以后引入的一个内存管理机制,专门用于缓存内核的数据对象,能够理解为一个内核专用的对象池,能够提升系统性能并减小内存碎片。(Linux 2.6.23以后,SLUB成为了默认的allocator。)ide
查看Slab缓存性能
$ cat /proc/meminfo
其中,Slab相关的数据为测试
Slab: 154212 kB SReclaimable: 87980 kB SUnreclaim: 66232 kB
SReclaimable(Linux 2.6.19+)都是clean的缓存,随时能够释放。回到以前的内存问题,我查了下那台服务器上Slab占用的内存:
$ cat /proc/meminfo | grep Slab Slab: 12777668 kB
12G的Slab缓存,有意思的是free把Slab缓存统计到了used memory中,这就是以前那个问题的症结所在了。
另外,还能够查看/proc/slabinfo
(或使用slabtop命令)来查看Slab缓存的具体使用状况。结果发现,ext3_inode_cache和dentry_cache占用了绝大部份内存。
考虑到这台服务器会频繁地用rsync同步大量的文件,这个结果也并不意外。
先说明一下,若是问题仅仅是Slab占用了太多的内存(SReclaimable),那么一般不须要太操心,由于这根本不是个问题(若是是SUnreclaim太多且不断增加,那么颇有多是内核有bug)。可是,若是是由于Slab占用内存太多而引发了其余的问题,建议继续阅读。
经过/proc/sys/vm/drop_caches
这个配置项,咱们能够手动清除指定的可回收缓存(SReclaimable)2。
echo 2 > /proc/sys/vm/drop_caches
上面的命令会主动释放Slab中clean的缓存(包括inode和dentry的缓存),而后再free -g
一下,未使用的内存陡增了十几个G。。。
须要注意的是,手动清除缓存可能会在一段时间内下降系统性能。原则上不推荐这么作,由于若是有须要,系统会自动释放出内存供其余程序使用。
另外,手动清除Slab缓存是一个治标不治本的办法。由于问题不在Slab,而在于咱们那个会引发Slab缓存飙涨的进程(我这里应该是rsync)。实际操做的时候发现,清除缓存一段时间后,Slab缓存很快又会“反弹”回去。若是须要治本,要么搞定问题进程,要么修改系统配置。
风险预警: 调整如下系统配置可能会对系统性能形成负面影响,请仔细测试并谨慎操做。
/etc/sysctl.conf
里有几个对内存管理影响比较大的配置,如下配置项的文档见vm.txt。
系统在进行内存回收时,会先回收page cache, inode cache, dentry cache和swap cache。vfs_cache_pressure越大,每次回收时,inode cache和dentry cache所占比例越大3。
vfs_cache_pressure默认是100,值越大inode cache和dentry cache的回收速度会越快,越小则回收越慢,为0的时候彻底不回收(OOM!)。
图片取自The Linux Kernel's VFS Layer
系统的"保留内存"的大小,"保留内存"用于低内存状态下的"atomic memory allocation requests"(eg. kmalloc + GFP_ATOMIC),该参数也被用于计算开始内存回收的阀值,默认在开机的时候根据当前的内存计算所得,越大则表示系统会越早开始内存回收。
min_free_kbytes过大可能会致使OOM,过小可能会致使系统出现死锁等问题。
该配置用于控制系统将内存swap out到交换空间的积极性,取值范围是[0, 100]。swappiness越大,系统的交换积极性越高,默认是60,若是为0则不会进行交换。