tomcat服务无响应堆栈分析

tomcat服务突然无响应了,导出内存堆栈和线程堆栈,分析后发现是同步锁使用不合理导致的。

[root@prd-dtb-web-01 ~]# pgrep java
10472
[root@prd-dtb-web-01 ~]# jmap -heap 10472
Attaching to process ID 10472, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.111-b14

using thread-local object allocation.
Parallel GC with 2 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 1983905792 (1892.0MB)
   NewSize                  = 41943040 (40.0MB)
   MaxNewSize               = 661127168 (630.5MB)
   OldSize                  = 83886080 (80.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 487063552 (464.5MB)
   used     = 26314992 (25.095932006835938MB)
   free     = 460748560 (439.40406799316406MB)
   5.402784070362958% used
From Space:
   capacity = 72351744 (69.0MB)
   used     = 71945680 (68.61274719238281MB)
   free     = 406064 (0.3872528076171875MB)
   99.43876404693161% used
To Space:
   capacity = 84934656 (81.0MB)
   used     = 0 (0.0MB)
   free     = 84934656 (81.0MB)
   0.0% used
PS Old Generation
   capacity = 254279680 (242.5MB)
   used     = 136744120 (130.40935516357422MB)
   free     = 117535560 (112.09064483642578MB)
   53.77705367570071% used

36326 interned Strings occupying 4333960 bytes.
[root@prd-dtb-web-01 ~]# jmap -dump:file=dump_dtb  10472
Dumping heap to /root/dump_dtb ...
Heap dump file created

[root@prd-dtb-web-01 ~]# jstack 10472 > thread_dtb

使用Eclipse MemoryAnalyzer对内存堆栈的分析,发现线程已经占满了。

通过对线程堆栈文件内容的分析,发现大量线程都处于waiting to lock状态,进一步发现,对应代码使用了synchronized同步锁,一个线程内部访问数据库发生了超时,长时间占用了该锁,导致其它线程都处于等待状态。

...

"http-nio-8002-exec-26" #52 daemon prio=5 os_prio=0 tid=0x00007f951c01b000 nid=0x291e waiting for monitor entry [0x00007f9530dc9000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at cn.friendsure.tdtb.services.WeixinPayService.payed(WeixinPayService.java:273)
    - waiting to lock <0x000000008a9103b0> (a cn.friendsure.tdtb.services.WeixinPayService)
    at sun.reflect.GeneratedMethodAccessor264.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
    at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)

...

at cn.friendsure.tdtb.logics.OrderLogic.transferOrder(OrderLogic.java:531)
    - locked <0x000000008a9104e0> (a cn.friendsure.tdtb.logics.OrderLogic)
    at cn.friendsure.tdtb.services.WeixinPayService.transferOrder(WeixinPayService.java:478)
    at cn.friendsure.tdtb.services.WeixinPayService.payed(WeixinPayService.java:399)
    - locked <0x000000008a9103b0> (a cn.friendsure.tdtb.services.WeixinPayService)
    at sun.reflect.GeneratedMethodAccessor264.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

...

【解决方案

去掉不必要的同步锁。

【总结

涉及IO的方法,尽量不要使用synchronized关键字,如果一定要用,要确保程序逻辑中有明确的超时控制机制,并且超时时间不要太长。

原文地址:https://www.cnblogs.com/lavezhang/p/6106356.html