服务跑几天内存就翻倍、不重启必爆——这就是内存泄漏。这篇讲怎么确认泄漏、怎么定位到进程和代码位置、游戏服和常见服务的处置方案。命令全部可抄。
需要现成的游戏云服务器,可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上,主流游戏都能快速部署。
一、先确认「是不是真泄漏」
内存涨不一定是泄漏,先排除正常情况:
# 1. 看内存构成:cache/buffer 高是正常的(系统在缓存文件)
free -h
# 2. 看趋势:连续观察几小时
while true; do date; free -m | grep Mem; sleep 300; done
# 3. 判断标准| 现象 | 结论 |
|---|---|
| available 很低但 free 的 cache 很高 | 正常,系统在缓存,不慌 |
| used 持续涨、available 持续降、重启后恢复 | 真泄漏 |
| used 涨到某个值就平稳 | 正常预热(缓存、连接池建满) |
| 内存瞬间打满然后 OOM | 突发流量或失控请求,不一定是泄漏 |
确认泄漏的硬标准:同样负载下,内存随时间单调上涨,且回收不了(echo 3 > /proc/sys/vm/drop_caches 也下不来)。
二、定位到进程
# 按内存排序找元凶
ps aux --sort=-%mem | head -10
# RSS 持续增长的进程(隔一小时对比两次)
ps -eo pid,rss,etime,comm --sort=-rss | head -10
# 实时看
top -o %MEM找到嫌疑进程后,看它的内存构成:
# 进程的内存映射统计
pmap -x <PID> | tail -5
# /proc 里的明细:堆、栈、匿名映射各占多少
cat /proc/<PID>/status | grep -E "VmRSS|VmSize|VmData|VmStk"
# 如果是 Java:看堆和非堆
jstat -gcutil <PID> 1000 # 老年代占比持续涨=堆泄漏三、定位到代码位置(按技术栈)
3.1 Java
# 1. dump 堆(两次,间隔看增长对象)
jmap -dump:live,format=b,file=heap1.bin <PID>
sleep 600
jmap -dump:live,format=b,file=heap2.bin <PID>
# 2. 用 MAT 或 jhat 分析:对比两次 dump,增长的对象就是嫌疑3.2 Node.js
# 1. 生成堆快照(需要 --expose-gc 启动)
kill -USR1 <PID> # 或装 heapdump 模块
# 2. Chrome DevTools 加载 .heapsnapshot 分析3.3 C/C++(游戏服常见)
# 1. valgrind 跑一遍(慢但准,测试环境用)
valgrind --leak-check=full --show-leak-kinds=definite ./gameserver 2>&1 | tee vg.log
# 2. 线上不重启定位:gdb 挂上看内存块
gdb -p <PID> -batch -ex "call malloc_stats()"
# 3. AddressSanitizer(开发期编译时加,一跑就报)
gcc -fsanitize=address -g yourcode.c3.4 通用旁路法
# 持续记录进程的 RSS,泄漏曲线很直观
while true; do echo "$(date +%s) $(ps -o rss= -p <PID>)" >> /tmp/rss.log; sleep 60; done游戏服场景:帕鲁、方舟这类 C++ 服务端的泄漏,你修不了源代码,只能规律重启兜底:
# 每天凌晨重启(配合广播)
0 4 * * * systemctl restart palworld这就是为什么帕鲁服务器优化里把「定时重启」列为核心手段——泄漏修不了,绕过它。
四、OOM:内存爆掉时发生了什么
# 确认是不是 OOM 杀的
dmesg -T | grep -i "killed process" | tail -5
# 看哪个进程被选中(内核按 oom_score 挑"最该杀"的)
dmesg -T | grep -i "oom" | tail -20内核杀人的逻辑:内存耗尽时挑 oom_score 最高的杀——通常是占内存最多的。所以经常出现「数据库被杀了,泄漏的游戏服还活着」这种冤案。
保护关键进程:
# 给 MySQL 调低 oom_score(更不容易被杀)
echo -1000 > /proc/$(pidof mysqld)/oom_score_adj
# 或 systemd 服务里
# [Service]
# OOMScoreAdjust=-500紧急止血:
# 1. 加 Swap 争取时间(没配的立刻配)
fallocate -l 4G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
# 2. 重启泄漏进程
systemctl restart <泄漏服务>
# 3. 长期:限制进程内存上限,泄漏到顶自动重启(cgroup)
systemctl edit <服务名>
# 加:
# [Service]
# MemoryMax=2G
# Restart=alwaysMemoryMax 到了就杀重启——用可控重启代替不可控 OOM,这是生产环境管泄漏进程的标准姿势。Swap 原理见Swap 分区与内存优化。
五、容器里的内存泄漏
# 看容器内存曲线
docker stats
# 容器被 MemoryMax 杀掉的事件
dmesg | grep -i "memory cgroup out of memory"处置:mem_limit 设上限 + restart: unless-stopped,泄漏到顶自动重启,宿主机安全。容器资源限制全景见Docker 安全加固与资源限制。
六、排查流程图(文字版)
内存持续涨
├─ free 看 cache: cache 高? → 正常,不用管
├─ ps 找 RSS 增长进程
│ ├─ 自己代码 → dump/valgrind 定位到行 → 修 bug
│ ├─ 第三方服务(DB/缓存) → 查连接数/配置/慢查询
│ ├─ 游戏服等闭源程序 → 定时重启 + 内存上限兜底
│ └─ 查不出 → pmap/status 看构成,分块对比
└─ 已经 OOM → dmesg 确认 → Swap 急救 → 重启 → 再走上面流程七、预防清单
- [ ] 关键服务配
MemoryMax或mem_limit,泄漏可控 - [ ] Swap 必配(小内存机器的保险丝)
- [ ] 关键进程(DB)调低
oom_score_adj,别被冤杀 - [ ] 内存监控告警:85% 持续 10 分钟
- [ ] 每周看一次 RSS 趋势曲线
- [ ] 新服务上线前跑一轮 valgrind/堆分析
- [ ] 游戏服等闭源服务:凌晨定时重启写进 cron
监控部署见Prometheus 监控体系和Netdata 可视化监控,日常巡检模板见服务器日常巡检清单。
内存泄漏排查的核心是「对比」:时间维度对比(RSS 曲线)、空间维度对比(两次 dump)、配置维度对比(换机器/换版本还漏不漏)。定位到根因就修,修不了(闭源程序)就用 MemoryMax + 定时重启工程化兜底——这不丢人,这是生产环境的常规操作。
需要现成的游戏云服务器,可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上,主流游戏都能快速部署。延伸阅读:Swap 分区与内存优化、僵尸进程与 CPU 异常排查、幻兽帕鲁服务器优化与常见问题。
延伸阅读
- 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
- 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
- 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
- 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
- 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
- RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
- 短链接服务搭建:Shlink 自托管,链接数据自己掌握
- 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道

[...]0 9 * df -h / | awk 'NR==2 && $5+0>80 {print "磁盘空间:"$0}'; df -i / | awk 'NR==2 && $5+0>80 {print "inode:"$0}' | mail -s "资源告警" admin@example.com[...]
2026-10-15 回复
[...]redis-cli INFO stats | grep evicted大 Key 和热 Key 是 Redis 从「能跑」到「跑得好」的分水岭。记住三个动作:--bigkeys 每周跑一次、UNLINK 代替 DEL、热数据加本地缓存。Redis 就能又稳又快。需要现成的游戏云服务器,可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上,建站快速部署。延伸[...]
2026-10-15 回复
[...]netsh advfirewall firewall add rule name="GameRange" dir=in action=allow protocol=UDP localport=26901-26903完整的 Windows 环境准备(远程桌面连接、运行库安装、SteamCMD 用法、开机自启、8 个常见坑)见:《Windows 云服务器开服通用前置教程》→ htt[...]
2026-10-18 回复