前言:最近维护的一个项目在正式环境出现了OutOfMemeryError
错误,导致项目不能访问,本篇文章记录一下问题的排查过程以及解决办法。
一、解决思路
发生OOM
错误一般情况都是堆内存不足导致的,要查看具体的发生OOM
时堆内存的情况,需要把它dump
到本地,然后通过一些工具进行分析,才能大概的发现问题出在哪里。
二、dump文件
使用java
自带的jmap
命令,生成 hprof
文件。
jmap -dump:format=b,file=dump.hprof 23322
其中23322
是当前java
进程的进程号,可以通过jps -l
命令查看。
三、使用mat
工具分析 hprof
文件
mat
分析完后,给出了可能出现的问题如下
很明显,当前对内存中有两个类型的对象几乎占满了整个堆内存,一个是
byte[]
数组,一个是Http11OutputBuffer
对象。查看details
,发现这两个问题都来自于tomcat
。进一步打开Histogram
第一行,
byte[]
数组有2612个,占据了840007864(约800M)的空间,基本上可以确定是它导致了OOM
问题。再查看
byte[]
的List Objects
可以看到,
byte[]
都是来自于请求get
请求。分析问题:正常的get请求
tomcat
不可能会创建这么大的对象,而且每次创建的byte[]
大小都相同,一定是哪里配置了。突然想起来之前项目有个导出功能,如果选择的条数过多的话,后台会提示Request header is too large
错误,查阅资料发现是tomcat
对请求头的大小做了限制,于是我修改了server.xml
的配置,将maxHttpHeaderSize
一点点调大了,设置为83886080,正好与byte[]
数组的大小相同,问题找到了。将配置删除后,问题就解决了。
后记::其实当线上发现这个问题的时候,我通过
-Xms
和-Xmx
直接调大了堆内存的大小,问题就没有再出现了,这也是大多数人解决OOM
问题的办法。