记一次JVM内存溢出造成的tomcat假死排查

今天中午公司老官网挂了,无法访问。领导让我帮同事排查。

首先NGINX没有问题,其他网站都能访问。

然后telnet访问tomcat端口。发现端口已经无法访问。但应用仍在服务器上运行。初步判断是tomcat假死造成的。而能造成tomcat假死的多半就是jvm出问题了。

马上在tomcat启动文件中加入jvm的rmi监控命令和gc日志打印命令。应用重启之后,立马发现了端倪。cpu和内存消耗居高不下。


然后查看GC时间,不看不知道,一看吓一跳。刚刚启动FULL GC已经到达了1分钟。并且年轻代没有什么GC。


再看看GC日志,发现每秒钟都在full gc。但是gc之后内存并没有释放。


当时我分析,java程序里的对象直接跳过年轻代,进了老年代。JVM对象大到一定程度的时候年轻代就放不下了。全都被移进老年代了,而能产生这么大对象的方式只有查数据库了,而且是查出了非常多的数据,多到年轻代都放不下。。。我猜多半是写了个笛卡儿积出来,然后在那资源死锁了。但光知道没用啊,要把代码找出来。找到那根死锁的线程。

这就必须要去查JVM的堆栈信息了。

首先拿到tomcat的PID:ps -ef | grep tomcat

然后查看tomcat下消耗性能最多的线程:top -Hp pid


前面4个线程都是JVM的GC线程,只有第5个线程最可疑。

通过printf "%x\n" 23978打印出这个线程的16进制值

然后通过命令打印出tomcat的堆栈日志 jstack pid> stack.log

通过搜索堆栈日志终于找出问题了,原来是json死循环+hibernate无限查数据库,造成内存溢出了。因为是很老的系统,用的还是用的hibernate+struts2。因为返回json时候查询关联关系的问题,造成系统死循环,无限查询数据库。这是很hibernate一个经典的BUG了,没想到现在还会出现在公司。



找出来的系统的堆栈日志,状态为BLOCKED 。

"http-12002-73" daemon prio=10 tid=0x00007f6ef8097000 nid=0x5edf waiting for monitor entry [0x00007f6f34236000]
   java.lang.Thread.State: BLOCKED (on object monitor)
at java.util.Arrays.copyOf(Arrays.java:2367)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:415)
at java.lang.StringBuilder.append(StringBuilder.java:132)
at java.lang.reflect.Method.toGenericString(Method.java:495)
at java.beans.MethodRef.find(MethodRef.java:79)
at java.beans.MethodRef.get(MethodRef.java:62)
at java.beans.PropertyDescriptor.getReadMethod(PropertyDescriptor.java:206)
- locked <0x0000000783891d60> (a java.beans.PropertyDescriptor)
at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:201)
at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:178)
at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:168)
at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:134)
at org.apache.struts2.json.JSONWriter.array(JSONWriter.java:492)
at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:158)
at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:134)
at org.apache.struts2.json.JSONWriter.add(JSONWriter.java:401)
at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:231)
at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:178)
at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:168)

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值