服务器内存占用过高怎么办?从排查到优化的完整指南
- 一、先读懂内存数据:free -h 各字段含义详解
- 二、快速定位内存占用最高的进程
- 三、判断是内存泄漏还是正常使用
- 四、8 种内存优化方案(按场景分类)
- 五、配置 Swap 交换空间作为应急缓冲
- 六、设置内存告警,提前预警
- 七、各技术栈内存占用参考基准
- 八、常见问题解答(FAQ)
一、先读懂内存数据:free -h 各字段含义详解
很多人看到内存使用率 80% 就开始慌,其实 Linux 的内存管理机制和 Windows 完全不同,未必需要立刻处理。先学会正确解读数据。
执行 free -h,输出结果类似:
total used free shared buff/cache available Mem: 3.8G 2.9G 156M 52M 780M 680M Swap: 1.0G 320M 704M
| 字段 | 含义 | 关注重点 |
|---|---|---|
total | 服务器总物理内存 | 硬件上限 |
used | 已使用内存(含 buff/cache) | 不能只看这个 |
free | 完全空闲的内存 | 通常很小,属正常 |
buff/cache | 系统用于缓存的内存,可随时释放 | 不算"真正占用" |
available | 真正可用内存(free + 可释放 cache) | 这才是关键指标 |
Swap used | 已使用的交换空间 | 有值说明物理内存已紧张 |
available 字段。当 available 低于总内存的 10%,才需要认真排查。判断内存状态的三个级别:
| available 占总内存比例 | 状态 | 建议 |
|---|---|---|
| > 30% | 正常 | 无需处理 |
| 10%–30% | 需关注 | 观察趋势,排查占用高的进程 |
| < 10% | 危险 | 立即排查,OOM 风险高 |
| Swap 有大量占用 | 严重 | 物理内存不足,需优化或扩容 |
二、快速定位内存占用最高的进程
1 用 top / htop 实时查看
# 启动 top,按 M 键按内存排序 top # 进入后按 Shift+M 按内存使用率排序 # htop 更直观(需先安装) apt install htop -y # Debian/Ubuntu yum install htop -y # CentOS htop # F6 选择排序字段,选 MEM% 按内存排序
2 用 ps 命令输出内存排行榜
# 按内存占用降序列出前 15 个进程 ps aux --sort=-%mem | head -15 # 输出格式:USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND # RSS = 实际占用物理内存(单位 KB),这是最重要的列 # 按进程名汇总内存(适合多进程服务如 PHP-FPM) ps aux | awk '{arr[$11]+=$6} END {for (i in arr) print arr[i], i}' | sort -rn | head -15
3 用 smem 精准统计共享内存
# smem 能区分共享内存,统计更准确 apt install smem -y smem -r -k | head -15 # 按进程名汇总 smem -r -k -t -P nginx
三、判断是内存泄漏还是正常使用
内存占用高分两种情况,处理方式完全不同:
| 类型 | 特征 | 处理方式 |
|---|---|---|
| 正常使用 | 内存随业务量增长,业务低谷期自动回落;重启服务后恢复正常 | 优化配置参数或升级内存 |
| 内存泄漏 | 内存单调递增,即使业务量低也不回落;持续运行时间越长占用越高;重启后暂时恢复 | 排查代码 bug,更新软件版本 |
用以下命令监控进程内存变化趋势:
# 每 5 秒打印一次指定进程(如 php-fpm)的内存使用 watch -n 5 "ps aux | grep php-fpm | grep -v grep | awk '{sum += \$6} END {print sum/1024 \" MB\"}'" # 记录 MySQL 内存占用历史(每分钟一次,记录 60 分钟) for i in $(seq 1 60); do echo "$(date): $(ps aux | grep mysqld | grep -v grep | awk '{print $6/1024 " MB"}')" sleep 60 done
四、8 种内存优化方案(按场景分类)
1 优化 MySQL / MariaDB 内存配置
MySQL 是服务器内存的头号消耗者,默认配置往往针对大内存服务器,在 1–4G 内存的 VPS 上需要大幅调低。
# 查看当前 MySQL 内存配置 mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';" # 编辑 MySQL 配置文件 nano /etc/mysql/mysql.conf.d/mysqld.cnf # Ubuntu nano /etc/my.cnf # CentOS
针对不同内存规格的推荐配置:
| 服务器内存 | innodb_buffer_pool_size | 其他关键参数 |
|---|---|---|
| 1G | 128M | key_buffer_size=16M |
| 2G | 256M | key_buffer_size=32M |
| 4G | 512M–1G | key_buffer_size=64M |
| 8G | 2G–4G | key_buffer_size=128M |
# 推荐配置示例(2G 内存 VPS) [mysqld] innodb_buffer_pool_size = 256M key_buffer_size = 32M tmp_table_size = 32M max_heap_table_size = 32M max_connections = 100 thread_cache_size = 8 # 重启 MySQL 使配置生效 systemctl restart mysql
2 优化 PHP-FPM 进程数
PHP-FPM 采用进程池模型,每个 worker 进程占用约 20–40MB 内存。进程数过多是 WordPress / PHP 网站内存超标的主要原因。
# 查看当前 PHP-FPM 进程数和内存占用 ps aux | grep php-fpm | grep -v grep | wc -l ps aux | grep php-fpm | grep -v grep | awk '{sum+=$6} END {print sum/1024 " MB"}' # 编辑 PHP-FPM 配置 nano /etc/php/8.1/fpm/pool.d/www.conf
根据内存调整进程数公式:最大进程数 = (可用内存 × 0.7) ÷ 单进程内存
| 服务器可用内存 | 推荐 pm.max_children | pm 模式 |
|---|---|---|
| 512MB | 5–8 | ondemand |
| 1GB | 10–15 | ondemand |
| 2GB | 20–30 | dynamic |
| 4GB | 40–60 | dynamic |
# 小内存 VPS 推荐配置(1G 内存) pm = ondemand pm.max_children = 10 pm.process_idle_timeout = 10s pm.max_requests = 200 # 重启 PHP-FPM systemctl restart php8.1-fpm
3 优化 Nginx worker 进程
# 编辑 Nginx 主配置 nano /etc/nginx/nginx.conf # 关键参数优化 worker_processes auto; # 自动匹配 CPU 核数,不要设置过大 worker_connections 1024; # 每个 worker 最大连接数 keepalive_timeout 30; # 降低长连接超时,释放内存 client_body_buffer_size 16k; # 限制请求体缓冲 large_client_header_buffers 2 8k;
4 关闭不必要的系统服务
# 查看所有开机启动的服务 systemctl list-units --type=service --state=running # 常见可安全关闭的服务(根据实际需要判断) systemctl disable --now postfix # 本地邮件服务(不发邮件可关) systemctl disable --now cups # 打印服务(服务器不需要) systemctl disable --now bluetooth # 蓝牙服务(服务器不需要) systemctl disable --now avahi-daemon # mDNS 服务(通常不需要)
5 优化 Redis 内存上限
# 编辑 Redis 配置,设置最大内存和淘汰策略 nano /etc/redis/redis.conf # 添加或修改以下配置 maxmemory 256mb # 根据服务器内存设置上限 maxmemory-policy allkeys-lru # 内存满时淘汰最久未使用的 key systemctl restart redis
6 清理系统 buff/cache 缓存
注意:这只是临时释放缓存,不解决根本问题,且可能短暂影响 I/O 性能。紧急情况下使用。
# 清理 PageCache(最安全) sync && echo 1 > /proc/sys/vm/drop_caches # 清理 dentries 和 inodes sync && echo 2 > /proc/sys/vm/drop_caches # 清理全部缓存 sync && echo 3 > /proc/sys/vm/drop_caches # 释放后立即查看效果 free -h
7 优化 Node.js 内存限制
# Node.js 默认堆内存上限约 1.5GB,可根据服务器内存调整 # 启动时指定最大内存(单位 MB) node --max-old-space-size=512 app.js # 限制为 512MB # PM2 管理的应用,在 ecosystem.config.js 中设置 module.exports = { apps: [{ name: 'myapp', script: 'app.js', node_args: '--max-old-space-size=512', max_memory_restart: '600M' // 超过 600M 自动重启 }] }
8 使用 OOM Score 保护关键进程
当内存耗尽时,Linux OOM Killer 会自动杀死进程。通过调整 oom_score_adj 可以控制哪些进程优先被杀,保护关键服务。
# 值范围:-1000(永不被杀)到 1000(优先被杀) # 保护 Nginx 不被 OOM 杀死 echo -500 > /proc/$(pgrep -f nginx | head -1)/oom_score_adj # 保护 MySQL echo -800 > /proc/$(pgrep mysqld)/oom_score_adj # 查看某进程当前的 oom_score cat /proc/$(pgrep mysqld)/oom_score
五、配置 Swap 交换空间作为应急缓冲
Swap 是在磁盘上划出一块空间模拟内存,当物理内存不足时系统会将部分数据转移到 Swap。速度比物理内存慢很多,但能防止 OOM 崩溃。很多云服务器默认没有开启 Swap,建议手动添加。
# 检查是否已有 Swap swapon --show free -h # 创建 2G 的 Swap 文件(根据内存大小调整,建议为内存的 1–2 倍) fallocate -l 2G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile # 验证 Swap 已启用 free -h # 设置开机自动挂载(将以下行添加到 /etc/fstab) echo '/swapfile none swap sw 0 0' >> /etc/fstab # 调整 swappiness(建议设为 10,减少 Swap 使用频率) echo 'vm.swappiness=10' >> /etc/sysctl.conf sysctl -p
六、设置内存告警,提前预警
出现内存问题时能第一时间收到通知,比事后救火重要得多。以下是一个简单的内存监控脚本:
#!/bin/bash # 内存告警脚本:当 available 低于 10% 时发送告警 # 保存为 /usr/local/bin/mem_alert.sh,chmod +x 后加入 crontab THRESHOLD=10 # 告警阈值(百分比) TOTAL=$(free | awk '/Mem/{print $2}') AVAILABLE=$(free | awk '/Mem/{print $7}') PERCENT=$((AVAILABLE * 100 / TOTAL)) if [ $PERCENT -lt $THRESHOLD ]; then MSG="⚠️ 服务器内存告警:可用内存仅剩 ${PERCENT}%(${AVAILABLE}KB),请立即检查!" # 发送到系统日志 logger "$MSG" # 如已配置 mail,发送邮件 echo "$MSG" | mail -s "内存告警" admin@yourdomain.com fi # 加入 crontab,每 5 分钟检查一次 crontab -e */5 * * * * /usr/local/bin/mem_alert.sh
七、各技术栈内存占用参考基准
在优化之前,先了解「正常的内存占用」是多少,避免过度优化或盲目升配:
| 服务 / 技术栈 | 最小内存需求 | 推荐内存 | 说明 |
|---|---|---|---|
| 纯静态 Nginx | 50MB | 128MB | 极省内存 |
| WordPress(PHP-FPM + Nginx) | 256MB | 512MB–1GB | 插件越多占用越高 |
| MySQL(小型应用) | 256MB | 512MB–1GB | 取决于 buffer pool 配置 |
| Node.js 应用 | 128MB | 256MB–512MB | 取决于应用逻辑 |
| Redis(缓存) | 64MB | 128MB–256MB | 视数据量而定 |
| Java Spring Boot | 512MB | 1GB–2GB | JVM 开销大 |
| Docker(每个容器) | 64MB+ | 视应用而定 | 加上 Docker 引擎约 100MB |
| 完整 LNMP 环境 | 512MB | 1GB–2GB | 小流量网站最低配置 |
八、常见问题解答(FAQ)
Q1:内存占用 90% 但服务一切正常,需要处理吗?
需要结合 available 字段判断。如果 available 还有 500MB 以上,且 Swap 没有使用,说明大部分是 buff/cache 缓存,系统运行正常,无需处理。只有 available 持续低于总内存 10% 时才需要介入。
Q2:OOM Killer 杀了我的 MySQL 进程,怎么防止?
有三种方法:一是调低 MySQL 的 innodb_buffer_pool_size 减少内存占用;二是为 MySQL 进程设置负的 oom_score_adj 值降低被杀优先级;三是增加 Swap 空间给系统更多缓冲。从根本上解决需要升级服务器内存或优化应用减少内存使用。
Q3:重启服务器后内存正常,过几天又满了,怎么回事?
这是典型的内存泄漏表现。建议使用 watch 命令每隔一段时间记录各进程内存占用,找出持续增长的进程。常见原因包括:PHP 代码中的循环引用、Node.js 全局变量积累、MySQL 连接未正确释放等。定期重启相关服务是临时方案,彻底解决需要修复代码。
Q4:1G 内存的服务器能跑 WordPress 吗?
可以跑,但需要精细调优。建议:MySQL innodb_buffer_pool_size 设为 128M,PHP-FPM 最大进程数设为 8,开启 2G Swap,并安装 WP Super Cache 等静态缓存插件减少 PHP 请求量。日均 PV 在 3000 以内基本稳定,超过则建议升级到 2G 内存。
Q5:后浪云服务器内存不够用了,如何快速扩容?
后浪云云服务器支持在线升级配置,登录控制面板选择「升级套餐」即可快速扩容内存,停机时间通常在 5 分钟以内。如果当前套餐无法满足需求,也可以迁移到更高配置的独立服务器。
