内存天天跑满、服务被系统杀掉?先找出是谁在吃内存

来源:互联网 时间:2026-09-29

服务半夜挂了,早上一看进程没了,日志里只留一句 Killed,重启后又能跑,隔几天再挂一次。这不是程序自己退出的,是系统内存不够,被 OOM 机制强行干掉的。网站内存占用高怎么办这类问题,第一步是学会从系统日志里把凶手找出来,而不是盲目加内存条。

一、Killed 背后是 OOM 机制在动手

Linux 在内存不足且无法回收时,内核的 OOM Killer 会按一套打分规则挑一个进程杀掉,优先挑占用内存最大、得分最高的那个。被杀的往往不是罪魁祸首,而是恰好长得最胖的那个,比如你的 web 服务。所以光看谁死了没有用,得反推内存到底被谁占着。还有一种情况是容器环境,进程在容器内被杀,主机日志里看不全,要看容器自己的日志和内核记录。

二、从 dmesg 和系统日志里找证据

OOM 的现场记录在内核日志里。dmesg 看当前启动周期的内核消息,配合 -T 把时间戳转成人类能读的格式;不同发行版的系统日志文件不一样,CentOS 系在 /var/log/messages,Ubuntu、Debian 系在 /var/log/syslog。搜 killed process 关键字,会看到类似 Out of memory: Killed process 12345 (php-fpm) total-vm 与 anon-rss 的记录。anon-rss 就是它被杀那一刻的真实物理内存占用,记下这个数字,它告诉你单进程的上限在哪。

# 从内核日志和系统日志中定位 OOM 记录

dmesg -T | grep -i -E 'oom|killed process'

grep -i 'killed process' /var/log/messages 2>/dev/null

grep -i 'killed process' /var/log/syslog 2>/dev/null

# 记下被杀进程名与 anon-rss 数值

三、按内存占用排序,锁定真正的大户

拿到被杀时刻的内存数字,再去对比当前谁占得最多。ps aux 按 rss 降序排序,RSS 列单位是 KB,前十名基本能覆盖绝大部分内存。重点看两类:一类是数量多、单个体积小的进程,比如 php-fpm 开了几百个子进程,每个五十兆,加起来就是十几 G;另一类是单个进程体积巨大,比如 JVM、MySQL 缓冲池或者一个不认识的二进制文件。后一类如果是陌生名字,且 CPU 也长期跑满,要当成入侵事件处理,先断网再排查。

# 列出内存占用前十的进程

ps aux --sort=-rss | head -15

# 统计同类进程的总内存占用(以 php-fpm 为例)

ps -C php-fpm -o rss= | awk '{s+=$1} END {print int(s/1024) " MB"}'

四、限制它,而不是等系统来杀

找到大户之后有三条路。一是给服务设内存上限,用 systemd 的 MemoryHigh 和 MemoryMax,超限时系统优先回收该服务的内存而不是把整机拖死,下面是给 php-fpm 加的限制片段,要改的是数值,一般按该服务实际峰值的 1.3 倍来设。二是调小应用自身的并发,php-fpm 的 pm.max_children、MySQL 的缓冲池都是常见的超配项。三是留出余量,置换分区可以当缓冲,但别依赖它,物理内存才是根本。改完执行重载,再观察几天 dmesg 里有没有新的 Killed 记录,没有才算稳。

# /etc/systemd/system/php-fpm.service.d/limit.conf

[Service]

MemoryHigh=1500M

MemoryMax=1800M

# 生效:systemctl daemon-reload && systemctl restart php-fpm

# 验证:dmesg -T | grep -i 'killed process' 不再出现新记录

如果确认是内存泄漏,限制上限只能延缓,最终还是得回到代码里把未释放的连接和对象修掉;如果是业务正常增长,加内存或加机器才是解法。把每次 OOM 的日期、被杀进程、当时内存整理成一张表,连续出现就说明现有配置已经撑不住业务了。

相关阅读:

《网站内存占用高怎么办?定位吃内存进程与释放策略》

《Linux服务器常用命令记不住总要临时查?这几个组合覆盖八成日常操作》

《数据库越来越慢拖垮整站?从慢查询日志开始查》

相关文章

A5创业网 版权所有

返回顶部