Linux系统swap分区占用排查与高效清理指南
1. 为什么你的Linux系统突然变卡了最近我的Ubuntu服务器频繁出现卡顿打开htop一看物理内存明明还剩30%没用但系统响应速度却慢得像蜗牛。经过一番排查发现罪魁祸首是swap分区被吃掉了90%这种情况就像你的办公桌内存明明还有空间却非要把文件堆到地上swap去处理工作效率能不低吗swap本质上是一种应急内存当物理内存不足时系统会把暂时用不到的内存数据临时存放在磁盘上。但问题在于Linux内核有个叫swappiness的参数默认值通常是60它控制着系统有多积极把内存数据往swap里挪。有时候物理内存还很充裕系统就开始频繁使用swap这就是典型的过度交换现象。我遇到过最夸张的情况是一台16GB内存的机器物理内存才用了40%swap却已经被占用了8GB。用free -h命令查看时swap那行显示为8G/16G used这时候系统性能已经明显下降因为磁盘I/O成了瓶颈。2. 快速定位swap使用情况2.1 查看swap基础信息首先用这个组合命令快速获取swap全景图free -h swapon --show cat /proc/swaps输出示例total used free shared buff/cache available Mem: 15G 5.2G 7.1G 456M 3.2G 9.3G Swap: 2.0G 1.8G 200M NAME TYPE SIZE USED PRIO /swapfile file 2G 1.8G -2这里关键看三个指标Swap totalswap总量Swap used已用swap量/proc/swaps中的Filenameswap存储位置可能是分区如/dev/sda2也可能是文件如/swapfile2.2 深度分析swap占用元凶想知道具体是哪些进程在吃swap试试这个神器sudo smem -t -k -s swap -r输出示例PID User Command Swap USS PSS RSS 4567 mysql /usr/sbin/mysqld 1.2G 800M 850M 1.1G 7890 java /usr/lib/jvm/java-11-bi 500M 300M 320M 400M这个结果一目了然地显示MySQL吃了1.2G swapJava进程占了500M。我曾经用这个方法发现过一个异常日志服务它因为内存泄漏竟然占用了2.3G swap3. 安全清理swap的三种姿势3.1 临时释放swap推荐方案完全关闭swap再重新开启是最彻底的清理方式sudo swapoff -a sudo swapon -a这个命令序列的实际效果相当于把swap里的数据全部写回内存清空swap存储区域重新启用swap注意执行前务必确保物理内存有足够空间容纳swap中的数据可以用free -h确认available内存值大于used swap值。我有次在内存只剩1G的情况下强行操作直接导致OOM内存溢出kill掉了关键进程。3.2 针对性降低swappiness修改系统参数减少使用swap的倾向性# 查看当前值 cat /proc/sys/vm/swappiness # 临时修改为更保守的值重启失效 sudo sysctl vm.swappiness30 # 永久修改 echo vm.swappiness30 | sudo tee -a /etc/sysctl.conf这个数值范围是0-1000除非物理内存耗尽否则不用swap60默认值100积极使用swap在我的生产环境中数据库服务器设置为10Web服务器设为30是比较合理的。3.3 调整swap分区大小如果发现swap经常被填满可能需要扩容。以swap文件方式为例# 创建4G大小的swap文件 sudo fallocate -l 4G /swapfile_new sudo chmod 600 /swapfile_new sudo mkswap /swapfile_new # 启用新swap sudo swapon /swapfile_new # 确认生效 free -h # 永久生效编辑fstab echo /swapfile_new none swap sw 0 0 | sudo tee -a /etc/fstab曾经帮客户把1G的swap扩容到8G后系统卡顿问题立刻消失。不过要注意swap不是越大越好一般建议内存4Gswap内存大小×2内存4-16Gswap内存大小内存16Gswap16G4. 防患于未然的监控方案4.1 实时监控脚本把这个脚本加入crontab每小时检查一次#!/bin/bash THRESHOLD80 SWAP_USED$(free | awk /Swap/{printf %.0f, $3/$2*100}) [ $SWAP_USED -ge $THRESHOLD ] { echo 警告swap使用率已达${SWAP_USED}% smem -t -k -s swap -r | head -10 } /var/log/swap_monitor.log4.2 使用systemd服务监控更专业的做法是创建systemd服务# /etc/systemd/system/swap-alert.service [Unit] DescriptionSwap Usage Monitor [Service] ExecStart/usr/local/bin/swap-monitor.sh Restartalways # /usr/local/bin/swap-monitor.sh #!/bin/bash while true; do if [ $(free | awk /Swap/{print $3}) -gt 2000000 ]; then wall 警告swap使用超过2GB fi sleep 300 done这套方案在我管理的50多台服务器上稳定运行了3年成功预警过多次内存泄漏事故。5. 那些年我踩过的swap坑有一次客户报告说服务器每隔几天就会变卡查看监控发现swap使用率呈现锯齿状波动。最终定位到一个Python脚本会周期性加载大型数据集虽然代码里有gc.collect()但实际内存释放不及时。解决方案是在脚本中加入import resource resource.setrlimit(resource.RLIMIT_AS, (1_000_000_000, 1_000_000_000)) # 限制内存使用1GB另一个经典案例是某台服务器总是莫名其妙地使用swap即使物理内存很充裕。最后发现是某个内核参数的锅# 检查透明大页状态 cat /sys/kernel/mm/transparent_hugepage/enabled # 禁用透明大页 echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled这些经验告诉我盲目清理swap只是治标理解应用的内存使用模式才是治本。建议每个运维人员都应该定期用vmstat 1观察si/soswap in/out指标这是发现内存问题的金标准。