服务器内存告警了,打开top一看used很高,然后就不知道怎么查了。
这篇整理一下Linux内存排查的常用方法。
先看整体情况
free命令
free -h
total used free shared buff/cache available
Mem: 31Gi 18Gi 1.2Gi 234Mi 12Gi 12Gi
Swap: 2.0Gi 512Mi 1.5Gi
几个关键概念:
很多人看到free很低就慌了,其实不用。Linux会把空闲内存用来做缓存(buff/cache),这些内存在需要时可以被回收。
真正要关心的是available,它代表应用程序实际可用的内存。
为什么used高但没问题
free -h
# used: 28Gi
# free: 500Mi
# buff/cache: 10Gi
# available: 10Gi
虽然used显示28G,但其中10G是缓存。如果应用需要内存,系统会自动回收缓存。
只有available也接近0的时候才需要担心。
swap使用情况
free -h | grep Swap
# Swap: 2.0Gi 512Mi 1.5Gi
如果swap used不为0,说明物理内存不够用,系统把数据换到磁盘了。这会导致性能下降。
查看swap使用详情:
swapon --show
vmstat看内存趋势
vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 512000 123456 234567 789012 5 10 100 200 234 567 5 2 90 3 0
关键列:
si和so持续不为0,说明在频繁使用swap,性能会受影响。
找出内存大户
top/htop
top
按 M 可以按内存排序。
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12345 mysql 20 0 10.2g 8.5g 1234 S 5.2 27.4 1234:56 mysqld
23456 java 20 0 8.5g 6.2g 567 S 12.3 20.0 567:89 java
关键列:
ps命令
# 按内存排序显示进程
ps aux --sort=-%mem | head -20
# 只看特定列
ps -eo pid,user,rss,vsize,comm --sort=-rss | head -20
smem
比ps更准确,考虑了共享内存的分摊:
# 安装
apt install smem # 或 yum install smem
# 使用
smem -rs rss | head -20
PID User Command Swap USS PSS RSS
12345 mysql mysqld 0 8234567 8345678 8567890
看PSS比较准确。
分析单个进程
/proc文件系统
# 进程内存概况
cat /proc/12345/status | grep -E "^(VmSize|VmRSS|VmSwap)"
VmSize: 10485760 kB # 虚拟内存
VmRSS: 8765432 kB # 物理内存
VmSwap: 123456 kB # 使用的swap
内存映射详情
# 简单版
cat /proc/12345/smaps_rollup
# 详细版
cat /proc/12345/smaps | head -100
7f1234560000-7f1234590000 rw-p 00000000 00:00 0 [heap]
Size: 196 kB
Rss: 180 kB
Pss: 180 kB
...
pmap
pmap -x 12345 | tail -20
Address Kbytes RSS Dirty Mode Mapping
0000555555554000 1234 890 456 r-x-- mysqld
...
total kB 10485760 8765432 567890
具体问题排查
问题1:哪个进程在用swap
# 方法1:脚本
for pid in /proc/[0-9]*; do
swap=$(awk '/VmSwap/{print $2}'$pid/status 2>/dev/null)
if [ -n "$swap" ] && [ "$swap" -gt 0 ]; then
name=$(cat $pid/comm 2>/dev/null)
echo"$pid$name: ${swap}kB"
fi
done | sort -t: -k2 -n | tail -20
# 方法2:用smem
smem -rs swap | head -20
问题2:内存泄漏
如果某个进程的内存持续增长:
# 监控进程内存变化
whiletrue; do
ps -p 12345 -o pid,rss,vsz | tail -1
sleep 60
done
对于Java应用,用jmap分析堆:
jmap -heap 12345
jmap -histo 12345 | head -30
对于C/C++应用,用valgrind。
问题3:buff/cache过高
正常情况下buff/cache高不是问题。如果想手动释放:
# 清理pagecache
echo 1 > /proc/sys/vm/drop_caches
# 清理dentries和inodes
echo 2 > /proc/sys/vm/drop_caches
# 清理所有
echo 3 > /proc/sys/vm/drop_caches
注意:生产环境不建议经常做,会导致缓存失效,IO突增。
问题4:OOM Killer
系统内存不够时会杀进程,查看被杀的进程:
# 查看OOM日志
dmesg | grep -i "out of memory"
grep -i "killed process" /var/log/messages
# 看哪个进程被杀
dmesg | grep -i oom | tail -20
调整进程被OOM Kill的优先级:
# 查看当前值(-1000到1000,越大越容易被杀)
cat /proc/12345/oom_score_adj
# 设置(-1000表示永不被杀)
echo -1000 > /proc/12345/oom_score_adj
问题5:内存碎片
长时间运行的系统可能有内存碎片:
cat /proc/buddyinfo
Node 0, zone Normal 12345 6789 3456 1234 567 234 123 56 23 8 2
后面的数字代表各种大小的连续空闲页数量。如果小块很多、大块很少,说明碎片严重。
整理碎片:
echo 1 > /proc/sys/vm/compact_memory
优化配置
swappiness
控制系统使用swap的积极程度:
# 查看当前值(默认60)
cat /proc/sys/vm/swappiness
# 临时修改(0-100,越小越不爱用swap)
echo 10 > /proc/sys/vm/swappiness
# 永久修改
echo"vm.swappiness = 10" >> /etc/sysctl.conf
sysctl -p
数据库服务器通常设置成10或更低。
overcommit
控制内存申请策略:
# 查看
cat /proc/sys/vm/overcommit_memory
# 0:默认,内核自己判断
# 1:总是允许申请
# 2:不允许超过物理内存+swap
透明大页
有些应用(如数据库)建议关闭透明大页:
# 查看状态
cat /sys/kernel/mm/transparent_hugepage/enabled
# 临时关闭
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
命令速查
# 整体情况
free -h # 内存概况
vmstat 1 # 实时监控
# 进程排查
top # 按M排序
ps aux --sort=-%mem # 内存排序
smem -rs rss # 更准确
# 详细分析
cat /proc/PID/status # 进程内存信息
pmap -x PID # 内存映射
# OOM相关
dmesg | grep -i oom # OOM日志
cat /proc/PID/oom_score_adj # OOM优先级
# 清理缓存(慎用)
echo 3 > /proc/sys/vm/drop_caches
内存排查的核心:
平时没事别去清缓存,那是系统在帮你加速IO。
只有available低、swap频繁使用时才需要处理。