大家好,我是入错行的bug猫。(http://blog.csdn.net/qq_41399429,谢绝转载)
内存溢出定位问题一步到位,就算是小白也能轻松学会的教程(呕~
最近几天公司的报表系统内存炸了,代码又被人下毒了,隔一段时间就内存溢出宕机。
服务器内存和CPU像bug猫本猫的血压一样彪高!(╯‵□′)╯︵┻━┻
- 先在启动指令中添加
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./
,目的是让实例在内存溢出后,凭最后一口仙气输出堆栈信息;
./
指堆栈信息输出路径,按个人喜好,也可以换成其他目录。
顺便说一句,在启动参数中,带一个-
是JVM参数,有两个-
是Springboot参数。
- 等内存再次炸了之后,就可以在配置好的目录中,看见一个叫
java_pidxxxx.hprof
的文件,其中xxxx是一串数字,就是实例的pid;
把hprof文件下载到本地待用。压缩后下载更快,这个应该都会想到不用提醒吧?
- 在自己电脑中,进入Java的
jdk
bin
目录,比如:C:\Program Files\Java\jdk1.8.0_202\bin
;
这里面都是JDK的一些工具和应用程序,其中有一个叫jvisualvm.exe
靓仔!
双击没法运行滴!只能把jvisualvm.exe
拖到CMD窗口,然后回车键
才能运行!
建议修改一下jvisualvm.exe
的内存大小,不然又卡又慢又提示内存不足! (JVM:内存才给100兆怪我卡咯?)
进入C:\Program Files\Java\jdk1.8.0_202\lib\visualvm\etc
,编辑visualvm.conf
,找到visualvm_default_options
项,修改-J-Xmx
- 在弹出的界面右上角,依次:
文件
->装入
,文件类型选择堆Dump(*.hprof, *.*)
,选中从服务器上下载的hprof文件。
- 选择
类
,然后按实例数
降序,下方根据项目包名搜索,就可以看到哪个对象实例数量不正常;
图中DzdTkOrder
数量为52万,明显有猫腻! (눈_눈)
在类名上右键,选择在实例视图中显示
,会进入到另外一个界面实例数
- 在左侧随便选中一个
实例
,等待片刻,就可以在右上字段
看见这个实例的一些内容,然而这些信息都无关紧要;
在右下引用
显示的内容中,一个一个滴用鼠标右键,直到出现在线程中显示
,选中点击;
- 然后就进入了
概要
界面,展示线程调用栈。按照一般栈的显示尿性,越是重要的信息,越在后面。
可以把下方几十行数据,一起复制粘贴到文本文档中,然后再用项目的包名,逐一搜索检查,就可以找到具体是哪个方法出岔子了 凸( •̀_•́ )凸
最后原因是:某个Mapper文件的SQL冲突了,有个大聪明解决冲突的时候,把别人的where条件搞没了,导致查询表报的时候,一下查询了大量数据。
当然这是最理想的状态,很多情况下,是动态SQL写得有问题,在查询过程中内存就直接溢出了。
此时查看内存的实例分布,就是存在大量的byte[],但是就是不知道具体是哪个类。
这个时候就要使用plan B了
- 回到jvisualvm的
概要
窗口,在右侧检查
,查找20保留大小最大的对象
,点击查找,等上一根烟的时间:
默认是按从大到小排序,看见蓝色的可点超链接,直接点就对了
-
点击第一个ArrayList之后,发现又进入了熟悉的
实例数
窗口:
2.1 先看左边实例数列表,多点几下保留
,一定是要按从大到小排序。然后展开500个实例
,会发现有个实例特别特别滴大!
2.2 再看右边,ArrayList 的 size 值,已经达到21万了,肯定就是这个导致内存炸了。ByteArrayRow是数据库游标对象,说明是在查询数据库的过程中,内存就溢出了,还没来得及转成实体类。
2.3 老规矩,在下方引用
右键鼠标,点击在线程中显示,就又会跑的线程栈窗口。
-
线程调用栈
把下方几十行复制出来,到文本文档中,用项目包名搜索,就能定位到是哪个方法出问题了。
~THE END~
于是在炎炎夏日之中办公室内的人都吃上了某位热心肠同事请客的雪糕