记录一次线上服务器发生的内存溢出排查过程

发布时间:2026/10/21 10:35:02
记录一次线上服务器发生的内存溢出排查过程 前言在测试服务器发布服务后测试在测试过程中发现服务异常宕机了两次叫我去看看原因。排查过程首先我就先去服务器上看了看服务最后挂掉的结束日志并没有发现有什么异常的地方就像服务突然就挂掉一样。接下来就只有去看看服务的状况了使用 cat /proc/meminfo 查看下服务器的内存分布情况可以看到服务器被占用了比较多的内存空间缓冲区大小也比较小。接着我们看看到底是那个进程占用了服务器最多的资源使用top指令可以看到占用cpu资源最多的是进程号为31062的进程且占用cpu资源高达99.9%然后去看看到底那个线程出现的问题可以看到pid 为 31068 的线程占用的cpu 资源高达 99.5%就是这个线程没错了于是我准备导出它的堆栈日志看看什么意思不让导嘛我就去网上看了看资料发现网上大多说的是进程用户如果不一样的话不能导后面我切成了一样的用户也不能导不是说加H 可以看原因的嘛我就加H试了试结果报的是这样的错说无法打开二进制文件。结合网上的资料我想应该是进程已经死了linux已经把日志清理了所以无法导出堆栈日志。做了这一堆事情还没确定下是不是我们那个服务的进程出的问题所以我是用 jps 查看下java 进程可以看到31062 就是我们挂掉的那个商品服务的进程再看看java 虚拟机的gc运行状况可以看到年轻代和老年代空间都已经被占满了。再用jmap看看堆的情况可以看到 年轻代和老年代以及元空间的内存基本都被占满了发生内存溢出了这个时候我们可以猜测下要不是有定时任务一直在跑一直增加对象没有释放内存要不就是发生了死循环。这个时候服务器进程已经挂了我也不好一直占用服务器资源看情况比较测试还要继续测试所有我就本地启动服务看看它的运行状况。本地启动goodcenter服务在 jdk的 bin 目录下自带了监测java虚拟机的工具有 jconsole 和 jvisualvm 你用那个都可以我用的jvisualvm运行一段时间虚拟机运行情况如下可以看到在4.30之前服务还是运行得好好的但是在4.30过后服务的cpu使用、java堆占比急剧上升。这个时候我们可以点右上角的导出堆栈日志运用mat工具进行分析在远程服务上一般也就这么操作。但是由于我是本地启动的我直接本地看服务日志发现了一个sql一直在打印找到了sql 打印的地方发现了一个循环语句如下大概意思就是 先判断分类id不为空 再根据分类查找父级的分类把查找到的分类添加到 categories 集合中。看到好像也没有什么问题接着我看了一下数据库发现数据如下这个数据就有问题了50的父级id 是 51 然后找到 51 那51的父级id又是50这个不就照成死循环categories 集合一直添加数据就发生堆溢出了。其实照理来说根本不会出现这种数据肯定是那个测试没注意到修改数据库产生垃圾数据了直接把这条垃圾数据删除也就完事了。