linux 内存free少问题

本文深入探讨了一次在CentOS服务器上遇到的内存管理问题,详细解释了Linux内存管理机制中的Slab缓存,并提供了如何诊断和解决Slab缓存占用大量内存的方法。

转自网文:http://blog.atime.me/research/linux-ate-my-memory.html

最近在维护一台CentOS服务器的时候,发现内存无端"损失"了许多,free和ps统计的结果相差十几个G,搞的我一度又以为遇到灵异事件了,后来Google了许久才搞明白,特此记录一下,以供日后查询。

虽然天天都在用Linux系统办公,其实对它的了解也不过尔尔。毕业几年才迈入"知道自己不知道"的境界,我觉得自己丝毫没有愧对万年吊车尾这个称号 :(

问题描述和初步调查

同事说有一台服务器的内存用光了,我连上去用free看了下,确实有点怪。

$ 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进制计算,总内存可能比实际偏小)

这里大概介绍下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-writeShared libraries等内存优化机制的存在,这两者的统计结果通常是不一样的。但是一般情况下绝对不会相差十几个G,肯定是有什么隐藏的问题,Google了许久后发现,free没有专门统计另一项缓存: Slab。

Slab简介和进一步调查

Slab Allocation是Linux 2.2之后引入的一个内存管理机制,专门用于缓存内核的数据对象,可以理解为一个内核专用的对象池,可以提高系统性能并减少内存碎片。(Linux 2.6.23之后,SLUB成为了默认的allocator。)

查看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占用内存太多而引起了其他的问题,建议继续阅读。

清除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缓存很快又会“反弹”回去。如果需要治本,要么搞定问题进程,要么修改系统配置。

调整系统vm配置

风险预警: 调整以下系统配置可能会对系统性能造成负面影响,请仔细测试并谨慎操作

/etc/sysctl.conf里有几个对内存管理影响比较大的配置,以下配置项的文档见vm.txt

vm.vfs_cache_pressure

系统在进行内存回收时,会先回收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!)。

linux io caches

图片取自The Linux Kernel's VFS Layer

vm.min_free_kbytes

系统的"保留内存"的大小,"保留内存"用于低内存状态下的"atomic memory allocation requests"(eg. kmalloc + GFP_ATOMIC),该参数也被用于计算开始内存回收的阀值,默认在开机的时候根据当前的内存计算所得,越大则表示系统会越早开始内存回收

min_free_kbytes过大可能会导致OOM,太小可能会导致系统出现死锁等问题。

vm.swappiness

该配置用于控制系统将内存swap out到交换空间的积极性,取值范围是[0, 100]。swappiness越大,系统的交换积极性越高,默认是60,如果为0则不会进行交换。

参考资料

阅读资料


<think>我们正在讨论Linux内存管理中的free和buff/cache释放机制。根据用户的问题和提供的引用,用户希望了解Linux系统中free命令显示的内存信息中,buff/cache部分的释放机制,包括自动释放和手动释放的情况。 关键点: 1. free命令显示的内存信息中,buffers和cache(统称为buff/cache)主要用于缓存磁盘数据,以提高文件读写效率。 2. 当系统内存紧张(即free内存不足)时,内核会自动触发内存回收,释放buff/cache中的部分内存,以满足应用程序的内存需求。 3. 手动释放buff/cache的方法是通过写入/proc/sys/vm/drop_caches文件,但需要注意这可能会导致I/O飙升,因为内核需要确保缓存数据的一致性(比如脏数据写回磁盘)。 4. 自动释放是内核内存管理的基本机制,而手动释放通常不建议在生产环境中使用,除非有特定需求。 下面我将根据引用内容,逐步解释free和buff/cache的释放机制。 ### 1. **free命令中的内存分类** 在Linux中,使用free命令可以查看内存使用情况,输出通常包含以下几列: - `total`:总物理内存- `used`:已使用的内存(包括buff/cache中正在使用的部分)。 - `free`:未被使用的内存(真正空闲,未被任何程序或缓存使用)。 - `shared`:共享内存- `buff/cache`:被内核缓冲区(buffers)和页缓存(page cache)占用的内存- `available`:估计可用于启动新应用程序的内存,它等于free内存加上可回收的buff/cache部分。 根据引用[3]: > available = free + buffer + cache(理想计算方式,实际有误差) 注意:`available`是从应用程序角度看到的可用内存,它考虑了可回收的缓存。 ### 2. **buff/cache的作用** - **buffers**:用于存储磁盘块的元数据(如目录项、inode等),加速文件系统操作。 - **cache**:主要分为Page Cache(文件数据的缓存)和Buffer Cache(磁盘块的缓存),现在通常统称为Page Cache。 引用[1]和[2]指出: > cache用来做缓存,在内存够用时加快进程对文件的读写速度。 ### 3. **自动释放机制** 当系统内存不足(即free内存即将耗尽)时,内核会触发内存回收(reclaim)机制: 1. **回收目标**:主要针对buff/cache,尤其是使用较多的cache空间。 2. **回收过程**: - 内核首先检查缓存中的数据是否与磁盘上的数据一致(即是否为“脏数据”)。 - 对于干净的缓存(clean cache,即与磁盘一致),可以直接释放。 - 对于脏数据(dirty cache),需要先写回磁盘(同步),然后才能释放。 3. **影响**:回收过程中,由于需要写回脏数据,可能导致I/O使用率飙升(引用[1]和[2])。 引用[1]强调: > 释放的时候,需要确认cache中的数据和对应文件中的数据一致才能对cache释放,否则需要写入之后才释放。所以随着cache释放,io会飙升。 ### 4. **手动释放机制** 虽然内核会在需要时自动回收,但用户也可以手动强制释放缓存: - 通过写入`/proc/sys/vm/drop_caches`文件(引用[2]和[4]): ```bash echo 1 > /proc/sys/vm/drop_caches # 释放Page Cache echo 2 > /proc/sys/vm/drop_caches # 释放slab分配器中的对象(包括dentries和inode缓存) echo 3 > /proc/sys/vm/drop_caches # 同时释放1和2 ``` - **注意**: - 手动释放仅适用于非脏缓存(干净缓存),脏缓存不会通过这种方式释放(需要先同步)。 - 手动释放会导致缓存被清空,可能暂时降低系统性能(因为后续文件读取需要重新从磁盘加载)。 - 生产环境不建议频繁手动释放,除非在特定场景(如测试内存占用或遇到内存压力时临时处理)。 ### 5. **释放代价与建议** - **代价**:自动或手动释放缓存都可能引起I/O压力(引用[1]和[2])。 - **建议**: - 依赖内核自动管理:Linux内核的内存管理机制已经相当成熟,应优先让内核在内存紧张时自动回收。 - 避免手动释放:除非在明确需要立即释放内存的情况下(如性能测试或内存严重不足且自动回收未及时触发),否则不要手动释放(引用[1]:线上服务器最好不要手动释放)。 ### 6. **内存释放的监控** 可以使用以下工具监控内存释放情况: - `free -h`:动态观察free和available的变化。 - `vmstat 1`:查看内存回收行为(如cache和buffer的变化,以及swap活动)。 - `sar -r 1`:监控内存使用率。 ### 总结 Linux系统中的buff/cache内存会在内存不足时由内核自动回收,以满足应用程序的内存需求。回收过程伴随着I/O操作(尤其是脏数据写回),可能影响系统性能。手动释放缓存虽然可行,但通常不建议在生产环境中使用,除非有特殊需求。系统管理员应信任内核的内存管理机制,并通过监控工具观察内存使用情况。 §§相关问题§§ 1. 如何监控Linux系统中内存回收(reclaim)的实时行为? 2. 在手动释放buff/cache时,如何确保脏数据先被写回磁盘? 3. Linux内核中管理缓存的主要数据结构是什么? 4. 如何调整内核参数以改变内存回收的阈值或行为?[^1][^2][^3][^4]</think>### Linux内存管理中free与buff/cache的释放机制 #### 1. **内存分类与作用** - **free内存**:真正未被使用的物理内存,可直接分配给应用程序。 - **buff/cache内存**:由内核管理的缓存内存,用于加速系统性能: - **buffers**:缓存磁盘块元数据(如目录项、inode) - **cache**:缓存文件内容(Page Cache) - **available**:应用程序视角的可用内存,计算方式为: $$\text{available} \approx \text{free} + \text{buffers} + \text{cache}$$ (实际值受内核算法影响会有偏差)[^3] #### 2. **自动释放机制** 当系统内存不足时,内核自动触发回收: 1. **触发条件**:`free`内存即将耗尽,应用程序请求新内存 2. **回收优先级**: - 优先释放`cache`(文件缓存) - 其次释放`buffers`(元数据缓存) 3. **回收过程**: - 检查缓存数据与磁盘的一致性 - 对**脏数据**(修改未同步的缓存)执行写回操作 - 释放**干净数据**(与磁盘一致的缓存) 4. **性能影响**: - 大量脏数据写回会导致I/O飙升 - 回收期间系统响应延迟增加[^1][^2] > ⚠️ **关键限制**:缓存释放必须保证数据一致性。例如修改过的文件缓存需先写回磁盘才能释放,这是I/O飙升的根本原因[^1]。 #### 3. **手动释放机制** 通过修改内核参数强制释放: ```bash # 释放Page Cache echo 1 > /proc/sys/vm/drop_caches # 释放slab缓存(含目录项/inode缓存) echo 2 > /proc/sys/vm/drop_caches # 同时释放1+2 echo 3 > /proc/sys/vm/drop_caches ``` **注意事项**: - 仅释放**干净缓存**,脏数据仍需写回 - 生产环境慎用:可能导致性能抖动[^2][^4] - 临时措施:适用于测试环境或特定维护场景 #### 4. **内核设计原理** 1. **缓存价值权衡**: - 空闲内存=浪费资源 → 内核主动用空闲内存作缓存 - 内存紧张时 → 牺牲性能释放缓存保进程运行 2. **释放策略**: - LRU(最近最使用)算法优先释放旧缓存 - 内存水位控制:`min_free_kbytes`参数设定回收阈值 3. **特殊缓存处理**: - 共享内存(`shmem`)不可回收 - 内核 slab 缓存需特殊处理[^2] #### 5. **最佳实践建议** 1. **生产环境**: - 依赖内核自动管理,避免手动释放 - 监控`available`值而非`free` 2. **调优方向**: ```bash # 增加脏数据写回阈值(默认40%) sysctl -w vm.dirty_ratio=60 # 缩短脏数据刷新周期(默认5秒) sysctl -w vm.dirty_writeback_centisecs=500 ``` 3. **异常排查**: - `cache`持续增长:检查文件读写型进程 - `buffers`过高:排查文件系统操作频率 > 💡 **设计哲学**:Linux将空闲内存视为资源浪费,通过缓存最大化利用内存提升性能,仅在必要时回收[^3][^4]。 #### 总结 `buff/cache`的释放由内核自动触发,优先释放文件缓存(cache),需确保数据一致性导致I/O开销。手动释放仅作为临时手段,生产环境应依赖内核内存管理机制,并通过`vm.dirty_*`参数优化回收行为。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值