昨天又有小伙伴问我,为什么Linux服务器明明还有很多内存,但是应用却报内存不足?看了一眼他发的free命令截图,我就知道问题出在哪了。说实话,刚开始接触Linux的时候,我也被这几个数字搞得一头雾水。
今天就来聊聊free命令输出的这6个数字到底是什么意思,相信看完之后你就不会再被Linux的内存管理搞糊涂了。
当我们在Linux系统上执行free -h
命令时,通常会看到这样的输出:
total used free shared buff/cache available
Mem: 7.8G 2.1G 1.2G 156M 4.5G 5.2G
Swap: 2.0G 0B 2.0G
第一次看到这个输出的时候,我的内心是崩溃的。什么叫used了2.1G,但是available却有5.2G?这数学是体育老师教的吗?
其实这里面涉及到Linux内存管理的一些核心概念,理解了这些概念,你就能明白为什么会出现这种看似矛盾的情况。
total就是系统的总物理内存大小,这个没什么好说的。你买了8G内存条,这里显示的就是8G(当然会扣掉一些被内核占用的部分)。
不过有个小细节,有时候你会发现total显示的内存比你实际购买的要小一些。比如你买了8G内存,但是total只显示7.8G。这是正常的,因为有一部分内存被BIOS、内核等系统组件占用了。
我记得刚接触电脑那会儿,买了16G内存,结果发现系统只识别到15.6G,还以为是内存条有问题,其实这是正常现象。
这个used是最容易让人误解的。很多人以为used就是应用程序实际使用的内存,其实不是这样的。
used包括了:
所以你看到used很高,不代表你的应用程序真的用了那么多内存。很可能是Linux把大量内存用作了文件缓存。
我之前遇到过一个案例,服务器显示used了6G内存,开发同学吓坏了,以为是内存泄漏。结果一查发现大部分都是文件缓存,应用程序实际只用了1G多。
说到这里,肯定有人要问了:既然used包含了这么多东西,那我怎么知道到底是应用程序用的多,还是缓存用的多呢?
这个问题问得好,我来教你几个实用的方法。
最直接的方法就是查看/proc/meminfo
文件,它会把内存使用情况拆分得很详细:
cat /proc/meminfo | grep -E "(MemTotal|MemFree|MemAvailable|Buffers|Cached|SReclaimable)"
输出大概是这样的:
MemTotal: 8048484 kB
MemFree: 524288 kB
MemAvailable: 5242880 kB
Buffers: 204800 kB
Cached: 4096000 kB
SReclaimable: 512000 kB
这里面:
把这几个加起来,基本就是free命令里buff/cache那一列的值。
我经常用这个命令来快速判断内存都去哪了。如果Cached特别大,说明系统缓存了很多文件;如果Buffers很大,可能是有大量的磁盘IO操作。
想知道应用程序到底用了多少内存,最直接的就是看各个进程的内存占用:
# 按内存使用量排序显示进程
ps aux --sort=-%mem | head -10
# 或者用这个更直观的格式
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -10
这样你就能看到哪些进程是内存大户了。
image-20250918202445910
我还喜欢用这个命令来统计某个应用的总内存使用:
# 比如统计所有java进程的内存使用
ps aux | grep java | awk '{sum+=\$6} END {print "Total memory: " sum/1024 " MB"}'
free显示的是完全没有被使用的内存。注意,这里不包括被用作缓冲区和缓存的内存,因为这些内存在需要的时候是可以立即释放给应用程序使用的。
所以你经常会看到free的值很小,这是正常的。Linux的设计哲学就是"空闲的内存是浪费的内存",系统会尽可能地把空闲内存用作文件缓存,提高系统性能。
有些刚接触Linux的同学看到free只有几百MB就紧张得不行,其实完全没必要。只要available够用就行。
shared显示的是被多个进程共享的内存大小。这部分内存主要包括:
说实话,在日常运维中,我很少特别关注这个数值。除非你的应用大量使用了共享内存,否则这个值通常不会很大。
我见过一些使用Redis的系统,如果Redis配置了大量的共享内存,这个值会比较高。但大多数情况下,这个数字都不是重点关注对象。
这个是Linux内存管理的精髓所在。buff/cache包括:
Linux会把空闲内存用作文件缓存,这样当程序再次读取相同文件时,就可以直接从内存中获取,而不需要再次访问磁盘。这大大提高了系统的IO性能。
关键是,这部分内存在应用程序需要时可以立即释放。所以虽然它们被标记为"已使用",但实际上是可用的。
我记得有一次优化一个文件服务器的性能,发现系统把大量内存用作了文件缓存。刚开始还担心内存不够用,后来发现这正是Linux智能内存管理的体现,文件访问速度提升了好几倍。
虽然Linux的内存管理已经很智能了,但在某些场景下我们还是需要适当调整。
# 清理页面缓存
echo 1 > /proc/sys/vm/drop_caches
# 清理所有缓存
sync && echo 3 > /proc/sys/vm/drop_caches
注意:生产环境别随便清理,会影响性能。
控制swap使用倾向:
# 查看当前值
cat /proc/sys/vm/swappiness
# 调整为10(让系统优先回收缓存而不是使用swap)
echo "vm.swappiness = 10" >> /etc/sysctl.conf
控制缓存回收压力:
# 调整目录和inode缓存回收
echo "vm.vfs_cache_pressure = 50" >> /etc/sysctl.conf
数据库服务器:
vm.swappiness = 1
vm.vfs_cache_pressure = 150
文件服务器:
vm.swappiness = 10
vm.vfs_cache_pressure = 50
记住调整完要用sysctl -p
生效,然后观察系统表现。大多数情况下默认设置就够用了,别没事瞎调。
这个是最重要的指标!available显示的是应用程序可以使用的内存总量,包括:
简单来说,available = free + 可回收的buff/cache
这个数值才是你真正需要关注的。当available很低的时候,才说明系统内存真的不够用了。
我现在判断系统内存是否充足,主要就看这个available值。只要它保持在一个合理的水平,就不用担心内存问题。
# 查看swap使用情况
free -h
swapon --show
# 创建2G的swap文件
dd if=/dev/zero of=/swapfile bs=1M count=2048
# 设置权限
chmod 600 /swapfile
# 格式化为swap
mkswap /swapfile
# 启用swap
swapon /swapfile
# 永久生效,添加到fstab
echo '/swapfile none swap sw 0 0' >> /etc/fstab
image-20250918205004240
# 关闭swap
swapoff /swapfile
# 从fstab中删除对应行
sed -i '/swapfile/d' /etc/fstab
# 删除swap文件
rm /swapfile
如果是swap分区而不是文件,需要用fdisk重新分区,比较麻烦。所以我一般推荐用swap文件,灵活性更好。
记住,SSD硬盘上频繁swap会影响寿命,能加内存就别用太多swap。
让我用一个真实的例子来解释这些概念。假设我们有一台8G内存的服务器:
total used free shared buff/cache available
Mem: 7.8G 3.2G 0.5G 200M 4.1G 4.3G
看起来used了3.2G,free只有0.5G,是不是内存很紧张?
其实不是的。让我们分析一下:
如果这时候启动一个需要2G内存的应用,系统会自动释放一部分文件缓存,为新应用腾出空间。
当available真的很低时,Linux会启动一些内存回收机制:
我遇到过几次OOM的情况,通常是因为某个应用出现了内存泄漏,把available耗尽了。这时候系统日志里会有相关记录,可以通过dmesg命令查看。
除了free命令,还有一些其他工具可以帮助我们监控内存:
cat /proc/meminfo
可以看到更详细的内存信息:
cat /proc/meminfo | head -20
top
或htop
命令可以看到各个进程的内存使用情况。
对于生产环境,我建议设置监控告警。当available内存低于某个阈值时(比如总内存的10%),就发送告警通知。
很多人看到used很高就以为内存不够用了,这是最大的误区。记住,只有available才是真正需要关注的指标。
还有人喜欢手动清理缓存:
echo 3 > /proc/sys/vm/drop_caches
其实这通常是没必要的,甚至可能降低系统性能。Linux的内存管理机制已经很智能了,不需要我们手动干预。
我见过有些运维同学定期清理缓存,以为这样可以释放内存。其实这样做反而会降低系统性能,因为清理掉的缓存很快又会被重新建立。
还有一个误区是认为swap使用就代表内存不够。其实少量的swap使用是正常的,Linux会把一些不活跃的内存页面换出到swap,为活跃的数据腾出更多内存空间。只有当swap使用率很高,或者系统频繁进行swap操作时,才需要担心。
顺便说一下,不同版本的Linux在free命令输出上可能有些差异。
在比较老的系统上,你可能看不到available这一列,那时候我们通常用这个公式来估算可用内存:
可用内存 ≈ free + buffers + cached
但这个估算并不准确,因为不是所有的buffers和cached都可以被释放。所以现在的系统直接提供了available这个更准确的数值。
现在很多应用都跑在Docker容器里,容器的内存统计会有一些特殊性。
在容器内执行free命令看到的是宿主机的内存信息,而不是容器被分配的内存。要查看容器的内存限制和使用情况,需要用其他方法:
# 查看容器内存限制
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
# 查看容器内存使用
cat /sys/fs/cgroup/memory/memory.usage_in_bytes
image-20250918211312186
我之前就遇到过一个坑,容器内的应用报内存不足,但是free命令显示宿主机内存充足。后来才发现是容器的内存限制设置得太小了。
理解了这些内存概念之后,我们在做性能调优时就有了更清晰的思路。
如果发现系统IO性能不好,但是buff/cache很小,说明文件缓存没有充分利用。这时候可以考虑增加内存,让系统有更多空间用作文件缓存。
如果available经常很低,但是应用程序实际使用的内存并不多,可能是某些进程存在内存泄漏。这时候需要用工具分析具体是哪个进程在消耗内存。
我曾经优化过一个Web服务,发现它的响应时间很慢。分析后发现是因为内存不足,系统频繁进行磁盘IO。增加了内存之后,大量文件被缓存在内存中,响应时间提升了好几倍。
在日常工作中,我经常用这些命令组合来快速了解系统内存状态:
# 查看内存使用情况,按人类可读格式显示
free -h
# 每秒更新一次内存信息
watch -n 1 free -h
# 查看详细的内存信息
cat /proc/meminfo | grep -E "(MemTotal|MemFree|MemAvailable|Buffers|Cached)"
# 查看各进程内存使用排序
ps aux --sort=-%mem | head -10
有时候我还会写个简单的脚本来持续监控内存变化:
#!/bin/bash
while true; do
echo "$(date): $(free -h | grep Mem)"
sleep 60
done
这样可以观察内存使用的变化趋势,对于排查间歇性的内存问题很有帮助。
理解Linux的内存管理机制对于运维和开发都很重要。记住这几个要点:
下次再看到free命令的输出,你就不会被那些数字搞糊涂了。Linux的内存管理确实很智能,我们要做的就是理解它的工作原理,而不是跟它对着干。
说实话,刚开始学Linux的时候,我也经常被这些概念搞得头大。但是随着经验的积累,慢慢就理解了Linux设计者的良苦用心。现在回过头看,这套内存管理机制真的很优雅,既保证了系统性能,又最大化了内存利用率。
最后想说的是,内存管理是个很深的话题,这篇文章只是入门级的介绍。如果你想深入了解,建议去看看《深入理解Linux内核》这本书,里面有更详细的技术细节(后台私信可以免费领取电子版哈!)
当然了,对于大多数运维工作来说,理解这些基本概念就够用了。关键是要在实践中多观察、多思考,多重复的练习。重复多了就是积累,积累多了就是经验,经验多了就是应变!