Skip to content

OOM(OutOfMemoryError)故障排查

当系统启动后一起正常,但是使用一段时间后或者用户量多了之后就卡了,一直没响应,CPU使用率很高,重启服务后又正常了,这时很可能就是OOM了。

OutOfMemoryError原因

TIP

本章节中涉及到操作JVM启动参数的操作请参考Tomcat设置启动环境变量

1.java.lang.OutOfMemoryError: Java heap space

堆内存不够用了,堆内存32位系统最好大于1G,64位最好大于2G,但不要太大,太大会导致gc慢,更不要大于或接近物理内存大小,否则会使用交换空间虚拟内存严重降低系统性能。

解决方法

建议增大JVM启动参数-Xmx=2048m

2.java.lang.OutOfMemoryError: PermGen space

TIP

这个异常只对JDK7及以下版本,JDK8已经去掉了PermGen space,改为Metaspace了。JDK8最好设置参数-XX:MaxMetaspaceSize=256m,避免JVM无节制的使用内存。

PermGen space的全称是Permanent Generation space,是指内存的永久保存区域, 这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中, 它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对 PermGen space进行清理,所以如果你的应用中有很多CLASS的话(包括Spring动态产生的类),就很可能出现PermGen space错误。

解决方案

建议增加JVM启动参数-XX:MaxPermSize=256m

MaxPermSize参数表示JVM可用的最大PermGen space,MaxPermSize参数大小为32M,MaxPermSize不会占用Max Heap Size(-Xmx)中设置的大小,如果设置:-Xmx1024m -XX:MaxPermSize=256m,那么Max Heap Size是1024m,不是1024m-256m

3.java.lang.OutOfMemoryError: GC overhead limit exceeded

TIP

java.lang.OutOfMemoryError: GC overhead limit exceeded,这个是JDK6新添的错误类型。是发生在GC占用大量时间为释放很小空间的时候发生的,是一种保护机制。

JVM GC过程耗时很久但只回收了不到2%的可用内存,如果已经设置了Xmx参数,那么可能是由于某些用户操作导致系统长时间占用大量内存无法GC。在JSP导入大excel时,也会出现此错误提示。

解决方案

增加JVM启动参数-XX:-UseGCOverheadLimit,更多内容可参考网页调优JVM内存

OutOfMemoryError故障确诊

当系统cpu消耗很高,而且线程都在做gc的时候可能就是有OOM了,如何确诊呢:

看看最忙的线程在干啥

sh
top //显示耗费cpu的进程
top -p 进程号 -H //显示这个进程内最好分cpu的线程,把列出的pid转换成小写16进制可在JVM堆栈中找到堆栈信息

toppid

设置gc日志记录,并分析gc日志

给JVM设置gc日志记录:-verbose:gc -Xloggc:garbage-collection.log(参见oracle官方说明),然后使用网站gceasy分析日志:

分析日志1

分析日志2

当提示Our analysis tells that your application is suffering from memory leak. It can cause OutOfMemoryError, JVM to freeze, poor response time and high CPU consumption. 时就说明有内存漏洞了。

OutOfMemoryError故障排查

参数自动导出Heapdump

如果已经进行了合理的XmxXX:MaxPermSize设置,还是出现OutOfMemoryError,那需要咨询研发工程师排查问题,为了帮助研发工程师解决问题,增加如下JVM参数以便在出现OOM的时候获得JVM的HeapDump文件:

sh
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/store/dumpfiles

当下次出现OOM后JVM会产生heapdump文件在/path/to/store/dumpfiles 目录下,请自行修改/path/to/store/dumpfiles的具体位置,确保/path/to/store/dumpfiles是一个存在的目录,且启动JVM的系统用户有权限写这个目录,如果下次出现OOM,把HeapDump文件(很大,需压缩后)发送给研发工程师。

jmap命令导出Heapdump

如果系统日志已经发现OOM错误,而未配置-XX:+HeapDumpOnOutOfMemoryError参数,并且内存占用比较高,可以通过jdk自带的jmap命令导HeapDump。

sh
./jmap -dump:live,format=b,file=heap.hprof <pid>

分析heapdump文件

生产环境内存一般配置比较高比如10G左右,产生的heapdump文件比较大,可以使用现场测试环境服务器安装MAT,采用命令行进行分析,把分析的结果发给研发进行排除问题。

MAT下载

点击此处下载MAT,选择Linux(X86_64/GTK+).

配置MAT

解压之后,需要修改MAT的配置文件,打开MemoryAnalyzer.ini文件,修改-Xmx的值,使其大于hprof文件的大小,建议是其2倍大小。

执行分析命令

sh
./ParseHeapDump.sh heap.hprof org.eclipse.mat.api:suspects

执行以后会生成 xxxx_Suspects.zip 的压缩包,解压后打开其中的html页面即可看到结果。

微信公众号微信公众号:山川软件