摘要:生产环境出现报警,显示内存已达90%?别慌张!本文借助一个真实发生的案例,教导您运用free、ps以及/proc这三种方法,迅速分辨“缓存”与“泄漏”,精确找出占用内存的进程。
一、 事故现场:那个突然变慢的下午
“熊猫,服务器卡爆了,快看看!”
登录服务器,第一反应是看资源水位:
free -h
输出如下:
total used free shared buff/cache available
Mem: 1.8G 912M 185M 12M 721M 727M
Swap: 2.0G 7.8M 2.0G
异常信号,系统刚刚启动的时候,used仅仅才800M出头,然而在几分钟之后,就飙升到了912M。可是,奇怪的是,available也就是可用内存,居然还有727M。
关键矛盾在于,内存的确是在上涨,然而系统为何还没有崩溃呢,究竟是真正出现了泄漏情况,还是属于虚假警报呢?
二、 排查三板斧,附实战代码;第一板斧呢,是 free -h ,它能看透“缓存”的谎言。
好多新手一旦瞧见 used 数值变高了,就会慌张起来,实际上,很大的可能性是缓存(buff/cache)方面的问题。
关键指标解读:
结论:在这个例子当中,available剩余量还有700M以上,暂时不会出现问题,可是需要找出究竟是谁在导致其上涨。
2️⃣ 第二板斧:ps—— 抓出“现行犯”
既然内存少了,直接排序找出占用最高的进程:
# 按内存占用倒序排列,取前 5 名
ps aux --sort=-%mem | head -5
输出分析:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 56872 2.0 9.2 331228 172008 pts/1 S+ 15:00 0:00 python /tmp/cache_service_fast.py
root 2169 0.4 7.4 345046 134468 ? Sl 13:21 0:25 /usr/bin/gnome-shell
...
将目标锁定为,PID 是 56872 的,一个属于 Python 的脚本,它独自占据着 9.2% 的内存。

3️⃣ 第三板斧:/proc—— 确认“作案手法”
光看占比不够,我们要看它“只吃不吐”还是“吃完就吐”。
直接查看内核记录的内存状态:
# 第一次查看(记录基准线)
cat /proc/56872/status | grep VmRSS
# VmRSS: 172008 kB (约 172 MB)
# 等待 5 分钟,再次查看(确认趋势)
cat /proc/56872/status | grep VmRSS
# VmRSS: 564420 kB (暴涨至 564 MB)
铁证如山:RSS(常驻内存)只增不减。
最后的确定性质为:属于典型的那种内存泄漏情况。去告知开发人员,要着重对cache_service_fast.py里进行全局变量或者死循环式缓存的审查。
三、 加快查阅表:三条指令记下来,四、生产环境避免入坑指南(惨痛经验教训),误区一:内存满了便进行重启?
不对!重新启动只是解决表面问题,无法从根本上解决问题。要是存在代码错误(比如列表无限添加),那重新启动之后,过5分钟还是会出现问题爆发的情况。
误区 2:直接kill -9?
需谨慎使用!针对于Java或者Python服务而言,直接采用-9这种方式,极有可能致使数据出现丢失的情况,亦或是造成文件受到损坏。应当先试着去执行kill PID这个操作,也就是默认的-15,从而给程序留出一段能够留下“遗言”的时间。
误区 3:Swap 开了就没事?
那可真是错得离谱而又极其严重!一旦展开对Swap的运用,磁盘I/O会致使服务器陷入瘫痪状态,其糟糕程度比OOM(内存溢出)还要让人难以忍受。要是通过free -h呈现出Swap正在被使用且呈现持续增长的态势,那就必须马上着手处理!
五、 进阶:Java/Python 专项排查
要是发觉属于Java进程泄漏情况,仅仅查看RSS是不足够的,还需要:
# 查看 JVM 堆内存情况
jstat -gcutil 1000 5
如果发现 Python 进程,重点检查:
关于全局的列表与字典这一块,其是否在不间断地进行数据追加操作。对于装饰器缓存而言,其所使用的@lru_cache是否不存在上限。而循环引用方面,是否存在着未被释放的大型对象。六、 总结。
下次收到内存告警,按这个流程走:
使用 free -h 来确认水位,具体是查看 available 的数值。通过 ps 抓出罪魁祸首,也就是查看 %MEM 的情况。利用 /proc 确认泄漏,即查看 VmRSS 是否存在疯涨的现象。