这个命令是干啥的
free 命令用来查看系统内存使用情况。我刚学Linux的时候,看到 free -h 输出,第一反应是"完了,内存用了90%以上"。后来才知道 buff/cache 那部分大部分是可以回收的,不是真的被占用了。
现在你问任何一个干了两年以上的运维,"内存够不够"这个问题,他肯定先跑 free -h 然后看 available 那列。而不是看 used。这个认知差距,就是buffer/cache造成的。
基本用法(3分钟上手)
最常用的就这一条:
# 以人类可读的格式查看内存
free -h
输出大概长这样:
total used free shared buff/cache available
Mem: 7.6G 1.2G 1.5G 145M 4.9G 5.8G
Swap: 2.0G 200M 1.8G
关键看这几列:
- total:物理内存总量
- used:系统认为"在用"的内存(包括buffer/cache)
- free:完全空闲的内存
- shared:共享内存(多个进程共用,一般不大)
- buff/cache:内核用做缓冲和缓存的内存
- available:新进程可以使用的内存(这个才是真实可用值)
进阶骚操作
buffer和cache的区别
这两个东西经常被放在一起说,但本质不一样。
buffer(缓冲区):主要针对块设备(磁盘)的读写。比如你写数据到磁盘,不会马上写进去,先写到buffer,内核攒够了再一次性写。这样可以减少磁盘I/O次数。
cache(缓存):主要针对文件系统。比如你读了一个大文件,内容会被cache住,下次再读就直接从内存返回,不用再读磁盘了。
说人话版本:buffer是"等会儿再写",cache是"读过的记着"。
到底怎么判断内存是不是真的不够
有次线上服务卡顿,监控显示内存用了92%。我差点就申请加内存了。但仔细看了 free -h:
total used free shared buff/cache available
Mem: 15.6G 12.5G 0.8G 200M 2.3G 12.8G
used 显示用了12.5G,但 available 显示还有12.8G可用。说明 used 里大部分是cache,真有新进程来了,内核会释放cache给它用。这其实不是内存泄漏。
真正的内存紧张标志是 available 持续低于总内存的10%-20%。
怎么清理cache(但别乱用)
有时候测性能或者做测试,需要清一下cache看裸数据。生产环境一般不建议清。
# 清理page cache(页面缓存)
echo 1 > /proc/sys/vm/drop_caches
# 清理dentries和inodes(目录和索引节点缓存)
echo 2 > /proc/sys/vm/drop_caches
# 清理所有缓存(page cache + dentries + inodes)
echo 3 > /proc/sys/vm/drop_caches
我踩过的坑:有次在测试环境跑benchmark,忘了先清cache,结果第二次跑的"性能提升"全是因为数据在cache里。后面学乖了,测试前先跑一遍 echo 3 > /proc/sys/vm/drop_caches。
生产环境千万别这么干。清完cache后,所有原本hot的数据都要重新从磁盘读,业务会瞬间变慢。
swap的使用情况
swap是磁盘上划出来当内存用的区域。当物理内存不够时,内核会把不常用的内存页换到swap上。
# 查看swap使用情况
free -h | grep Swap
# 或者
swapon --show
swap用得多不一定是坏事,有时候内存够用也被swap了。但如果你发现交换量(si/so)持续很高,说明物理内存确实不够了。这时候加内存比优化代码管用。
以MB为单位查看(适合脚本处理)
# 以M为单位,方便在shell脚本里做计算
free -m
避坑指南
坑1:top命令里RES和free不一样
我早期排查问题的时候,top 里看每个进程的RES(常驻内存)加起来,跟 free 显示的used对不上。后来才明白:
- ·
free 的used包含了page cache和buffer - ·
top 的RES是每个进程实际占用的物理内存 - ·进程的RES有共享部分(共享内存库),如果简单相加会重复计算
所以别纠结为什么对不上,用不同的工具看不同的维度。
坑2:used很高但available很高,到底要不要加内存
很多刚入行的同学看到 used 90% 就慌了。其实这时候要看 available。
available 是内核估算的"还能给新进程用多少"的值。它包括了free + 可以回收的cache + 一部分slab。这个值才是真实可用内存的上限。
如果used 90%但available还有60%,完全不用管。如果available低于总内存的10%,才需要关注。
坑3:内存泄漏的判断
内存泄漏的典型表现是 used 持续增长,且 available 持续下降,进程重启后内存会释放。
我遇到过的一个案例:Java进程内存泄漏,用 free -h 看available从20G慢慢降到2G。这时 ps aux --sort=-%mem 可以看到那个Java进程占用了绝大部分内存。
排查工具链:
# 1. 先用free看整体
free -h
# 2. 再用ps查TOP进程
ps aux --sort=-%mem | head -10
# 3. 再用top实时盯着
top -o %MEM
# 4. 最后用pmap看进程具体分配(确认泄漏)
pmap -x <PID>
坑4:docker里看free不准
在容器里跑 free 看到的其实是宿主机的内存,不是容器限制后的值。容器里的内存限制最好用 cat /sys/fs/cgroup/memory/memory.limit_in_bytes 或者 docker stats 来看。
# 查看容器实际可用的内存大小(cgroup v1)
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
# cgroup v2
cat /sys/fs/cgroup/memory.max
实战场景(重点!结合真实运维场景)
场景1:排查线上服务OOM
有次服务频繁被内核OOM killer杀掉,进程日志里能看到 Killed process。我排查过程:
# 1. 先看总内存情况
free -h
# 2. 发现available只剩不到500MB,肯定不够
# 3. 看哪个进程吃内存最多
ps aux --sort=-%rss | head -15
# 4. 看OOM killer日志
dmesg | grep -i "killed process"
# 5. 看swap使用
swapon --show
最后发现是一个SQL查询没加limit,查了500万行数据,内存直接炸了。
场景2:buffer/cache偏高导致误报
我们的监控系统报警:内存使用率超过90%。我上机器一看:
$ free -h
total used free shared buff/cache available
Mem: 31.2G 28.5G 0.2G 100M 2.5G 28.0G
used 28.5G,free只有200M,但available还有28G。原因是业务高峰期大量读文件,cache撑起来了。但监控拉的是used/total这个比例,导致误报。
跟监控组沟通后,把报警指标从"内存使用率"改成了"available < 总内存10%",之后再没误报过。
场景3:用free写巡检脚本
我写过的一个巡检脚本片段:
#!/bin/bash
# 获取内存可用百分比
TOTAL=$(free -m | awk '/^Mem:/ {print $2}')
AVAILABLE=$(free -m | awk '/^Mem:/ {print $7}')
PERCENT=$((AVAILABLE * 100 / TOTAL))
echo "总内存: ${TOTAL}MB"
echo "可用内存: ${AVAILABLE}MB"
echo "可用比例: ${PERCENT}%"
if [ $PERCENT -lt 20 ]; then
echo "⚠️ 内存紧张,建议排查"
elif [ $PERCENT -lt 10 ]; then
echo "🔴 内存严重不足,立即处理"
fi
场景4:跟top和htop配合的真实排查
有次排查性能问题,我用三个不同维度看内存:
# 维度1:全局角度
free -h
# 维度2:进程角度(看RSS排序)
top -o %MEM
# 维度3:内核角度(slab分配情况)
cat /proc/meminfo | grep -E "Slab|SReclaimable|SUnreclaim"
发现 SUnreclaim(不可回收的slab)异常高,查了下是dentry cache没被释放。最后发现是某个应用疯狂创建和删除大量小文件,导致内核的dentries缓存膨胀。
今日作业
你接到报警说服务器内存使用率已达95%。你ssh上去执行 free -h 看到如下输出:
total used free shared buff/cache available
Mem: 7.6G 6.8G 0.1G 200M 0.7G 4.5G
Swap: 2.0G 1.5G 0.5G
1. 分析这台机器的内存真实情况,available为什么只有4.5G?是不是真的不够了?
2. Swap用了1.5G,说明什么问题?
3. 如果你是运维,接下来你会怎么排查?
4. 写出用free写一个简单的shell脚本,当available小于2G时输出告警。