Ubuntu服务器内存不够用的时候,最直接的解决思路就两条:一是清理Linux内核自带的page cache和slab缓存,二是调整swap的使用策略让系统在内存紧张时更积极地把不活跃数据挪到磁盘上去。很多运维新手看到free命令里buff/cache占了好几个G就慌了,其实那是Linux正常的内存利用方式,不一定需要清理;但如果swap使用率长期飙高、系统开始卡顿,那就必须动手调优了。下面我把从诊断到优化的完整流程讲清楚。
一、先搞清楚Ubuntu内存和swap的真实状态
动手之前一定要先看数据。在终端执行free -h命令,你会看到类似这样的输出:total、used、free、shared、buff/cache、available这几列。重点关注available这一列,它才是系统真正可用的内存估算值。如果available还很充裕,哪怕free显示很低也不用紧张,因为buff/cache里的数据随时可以被内核回收。
再看swap使用情况,执行swapon --show或者cat /proc/swaps。如果swap分区或swap文件的used值持续增长且不回落,说明系统确实在频繁使用交换空间,这时候性能已经在下降了。另外用vmstat 1命令观察si和so两列,si表示每秒从swap读入内存的量,so表示每秒写入swap的量,如果这两个值长期不为零,说明内存压力很大。
二、手动清理内存缓存的具体操作
Linux内核会把频繁读取的磁盘数据缓存在内存里加速访问,这就是page cache。清理它的命令很简单,但要注意时机。先执行sync把磁盘缓冲区数据写回磁盘,避免数据丢失:
sync
然后清理page cache:
echo 1 > /proc/sys/vm/drop_caches
如果还要清理dentries和inodes缓存(目录项和索引节点缓存),执行:
echo 2 > /proc/sys/vm/drop_caches
如果三种缓存全部清理,执行:
echo 3 > /proc/sys/vm/drop_caches
这三条命令需要root权限,建议前面加sudo。清理之后用free -h再看一眼,buff/cache那一列应该明显下降。但要强调一点:这只是临时释放,系统运行一段时间后缓存又会慢慢涨回来,这是正常行为。不要把它当成长期解决方案,频繁手动清理反而会降低磁盘IO性能。
三、通过sysctl参数长期调优swap行为
真正要从根本上解决swap使用率高的问题,需要调整内核参数。编辑/etc/sysctl.conf文件,加入或修改以下参数:
vm.swappiness=10 vm.vfs_cache_pressure=50 vm.dirty_ratio=10 vm.dirty_background_ratio=5
vm.swappiness这个参数控制内核使用swap的积极程度,默认值是60,范围0到100。设为10意味着内核会尽量避免使用swap,只有在内存真的非常紧张时才会动用。对于有大量内存的服务器,设成10甚至1都可以;对于内存本身就小的机器,设成10能有效减少swap颠簸。设为0也不是完全禁用swap,而是极其保守地使用。
vm.vfs_cache_pressure控制内核回收目录项和inode缓存的倾向,默认100。降低到50可以让内核更愿意保留这些缓存,减少不必要的IO开销。
vm.dirty_ratio和vm.dirty_background_ratio控制内存中脏页(还没写回磁盘的数据)的比例阈值。降低这两个值可以让数据更频繁地写回磁盘,避免突然大量写入造成IO阻塞。改完之后执行sudo sysctl -p让参数立即生效。
四、检查和优化swap配置本身
很多Ubuntu服务器的swap是在安装时自动创建的swap文件,位置在/swapfile。先确认swap大小是否合理,一般建议swap大小等于内存大小或者内存的一半,具体看工作负载。查看当前swap大小:
swapon --show
如果需要调整swap大小,先关闭现有swap:
sudo swapoff /swapfile
然后重新创建指定大小的swap文件,比如8G:
sudo fallocate -l 8G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile
最后在/etc/fstab里确认有这一行,保证重启后自动挂载:
/swapfile none swap sw 0 0
如果你的服务器有多块磁盘,还可以考虑把swap放在独立的SSD上,和系统盘、数据盘分开,避免swap IO和业务IO争抢带宽。
五、用cgroups限制进程的内存占用
有时候swap使用率高不是因为总内存不够,而是某个进程吃掉了太多内存。比如Java应用、MySQL、Redis这些大户。可以用cgroups来限制单个进程或进程组的内存上限。创建一个内存限制为4G的cgroup:
sudo cgcreate -g memory:/limited_group echo 4G > /sys/fs/cgroup/memory/limited_group/memory.limit_in_bytes sudo cgexec -g memory:limited_group your_command
这样即使某个程序内存泄漏,也不会把整个系统的swap撑满。对于Docker容器场景,可以在docker run时直接指定--memory=4g参数,效果类似。
六、监控和自动化运维建议
优化不是一劳永逸的事,需要持续监控。推荐安装htop或glances这类工具实时观察内存和swap变化。更专业一点可以部署Prometheus加node_exporter,配合Grafana做长期趋势图,设置swap使用率超过70%就告警。
如果你经常需要清理缓存,可以写一个简单的crontab定时任务,但要谨慎设置频率,比如每周凌晨执行一次就够了:
0 3 * * 0 root sync && echo 3 > /proc/sys/vm/drop_caches
不建议每天甚至每小时清理,因为Linux的缓存机制本身就是为了提升性能而设计的,过度清理等于让系统每次都从磁盘重新读数据,得不偿失。
七、几个容易踩的坑和实战经验
第一,不要看到buff/cache高就去清理。Ubuntu的设计哲学就是"空闲内存是浪费的内存",内核会自动管理这些缓存,available才是真正该关注的指标。
第二,swap使用率高不一定是坏事。如果系统有大量不活跃的冷数据,放在swap里反而能腾出内存给活跃进程用。只有当si/so持续很高、系统响应变慢时才需要干预。
第三,调低swappiness不等于禁用swap。有些人把swappiness设成0以为就不用swap了,实际上在内存极端不足时内核还是会用,只是更晚才触发。对于数据库服务器,有时候反而需要适当提高swappiness(比如设成10-20),让内核更早把冷数据换出去,给数据库的buffer pool留更多空间。
第四,如果你的服务器经常OOM(Out of Memory),光调swap参数解决不了根本问题,需要从应用层面优化,比如减少内存泄漏、增加物理内存、或者做服务拆分。swap只是兜底手段,不是主力方案。
总结一下,Ubuntu内存缓存清理和swap优化是一套组合拳:先用free和vmstat诊断真实状态,必要时手动drop_caches救急,然后通过sysctl长期调优内核参数,合理配置swap大小和位置,用cgroups管控大内存进程,最后配合监控持续跟踪。把这几步做扎实,服务器的内存使用效率和稳定性都会有明显提升。
