赞
踩
巨大结果集引起疯狂FullGC怎么排查
笔者经常遇到这样一个问题。就是SQL写的不好,从数据库里面捞出来一个非常巨大的结果集,导致Java疯狂的进行Full GC,然后失去响应。找出来导致巨大结果集的sql有一个套路可以轻松找到。今天我就分享这个技巧
先dump再重启
遇到FullGC导致系统失去响应,那第一步当然是用jmap进行java的heap dump然后重启恢复。jmap命令如下:
jmap -dump:format=b,file=rheap.hprof [你的进程pid]
当然了,在JVM参数里面最好加上
-XX:+HeapDumpOnOutOfMemoryError
参数,这样在java进程在出现OOM的时候可以打印出dump文件,不至于找不到痕迹。
用MAT(MemoryAnalyzer进行分析)
由于素材并不在这台电脑上,所以就无法截图展示了。利用MAT打开dump文件之后,它会自动分析哪个占用的内存最大,并给出内存泄露信息。例如这样:
基本的排查方法就是看这个MAT提示有内存溢出的类是怎么产生的。毫无疑问,我们的巨大结果集肯定是SQL产生的。如何找到这个SQL呢?看下图: 我们可以做一下推理,如果还在FullGC,明显这个ResultSet还在内存里,那么对应的JDBC连接里肯定还在绑定这条sql,并不会被释放。同时这个系统最前端接收的调用请求肯定还在,因为这个请求还没有结束。如下图所示:
当我们从ResultSet按图索骥找到对应的JDBC Connection后,可以看到其中运行的SQL,这样我们就知道到底是哪个SQL了。
想知道SQL还不够?想知道哪个请求参数导致的?
很简单,由于我们的数据库交互基本都是在一个线程里面的。那么从ResultSet在MAT里面找到其中的CurrentThread,然后再在这个CurrentThread中找到你对应的Request请求类,就可以看到传输的参数了!由于JVM可达性的原理,这些对象肯定不会被回收。
还想更简单,更快吗?
就用MAT非常NB的OQL功能吧,看到某个结果集基本就能够想到哪几种请求会导致这个Request。直接用OQL Select那些请求Class,看一看就行了。因为请求一般很快,存留在heap dump中的很少。
使用OQL,例如BinaryOutpuArchive是你的请求参数,通过OQL搜索,会找到这个heapdump中的所有对象。并能够展示出对象中的所有信息。那么,如果一个请求参数不合理,就很容易看出来了!
总结
内存泄露问题大部分时候用MAT就可以解决问题,今天笔者介绍了一个小套路。怎么通过MAT方便的找到对应的SQL和对应的请求参数,希望能够对读者有所帮助。
END
推荐好文
原文始发于微信公众号(Java笔记虾):巨大结果集引起疯狂FullGC怎么排查
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。