一、jstack日志分析概述
jstack是一个Java虚拟机自带的工具,可以生成Java线程转储文件(常称为Java堆栈转储文件),输出当前JVM内所有线程的堆栈信息。jstack日志分析在调试Java程序时非常有用,可以用于检查线程是否被锁死,线程是否在等待请求响应等问题。通过jstack日志分析,我们可以更好地定位问题,提高问题定位效率。
二、生成jstack日志
生成jstack日志的方法非常简单,只需要执行以下命令:
jstack -l pid > jstack.log
其中,pid指的是Java进程的进程ID,jstack.log是生成的日志文件名称。
三、jstack日志分析工具介绍
在进行jstack日志分析时,有很多工具可以使用,下面我们介绍几个常用的工具:
1. Eclipse MAT
Eclipse MAT是一款基于Eclipse的Java堆分析器,可以用于检查Java线程状态,分析Java堆状态等问题。MAT可以处理Java堆转储文件,jstack输出文件等等。
2. jstack解析器
jstack解析器是一款开源的Java工具,可以对jstack输出的堆栈信息进行解析和分析,支持线程状态分析、死锁分析、线程间调用分析等等。
3. VisualVM
VisualVM是一个可视化的Java性能分析工具,可以用于监控Java应用程序的性能,并且提供了线程分析功能。可以通过VisualVM生成jstack日志,并且可以对日志进行分析。
四、jstack日志分析示例
1. 线程状态分析
jstack日志中,每个线程都有自己的状态,常见的线程状态包括Runnable、Waiting、Timed_Waiting、Blocked、In_Object_Wait等等。通过分析线程的状态,我们可以看到线程是否正在执行、是否被阻塞、是否在等待某个资源。
示例代码:
"Thread-141" #1224 prio=5 os_prio=0 tid=0x00007f364804d800 nid=0x588b waiting on condition [0x00007f364ddbc000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at com.example.demo.service.TestService.testMethod(TestService.java:16) at sun.reflect.GeneratedMethodAccessor66.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
2. 死锁分析
在jstack日志中,如果有线程被阻塞等待某个资源,而该资源又被其它线程所持有,则很可能发生死锁。通过jstack可以分析死锁线程,进一步了解死锁产生的原因,从而解决问题。
示例代码:
"Thread-1182" #1489 prio=5 os_prio=0 tid=0x00007fbf5c0e4800 nid=0x34f3 waiting for monitor entry [0x00007fbf3f3cf000] java.lang.Thread.State: BLOCKED (on object monitor) at com.example.demo.service.TestService.testMethod(TestService.java:26) - waiting to lock <0x00000007926d08d0> (a com.example.demo.entity.TestEntity) at sun.reflect.GeneratedMethodAccessor72.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) "Thread-1183" #1490 prio=5 os_prio=0 tid=0x00007fbf5c0eb000 nid=0x34f4 waiting for monitor entry [0x00007fbf3f2ce000] java.lang.Thread.State: BLOCKED (on object monitor) at com.example.demo.service.TestService.testMethod(TestService.java:26) - waiting to lock <0x00000007926d0118> (a com.example.demo.entity.TestEntity) at sun.reflect.GeneratedMethodAccessor72.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
3. 线程间调用分析
jstack日志可以展示线程之间的调用关系,对于分析代码调用链非常有帮助。我们可以通过jstack日志分析方法之间的调用顺序,了解程序的执行过程。
示例代码:
"Thread-1" #119 prio=5 os_prio=0 tid=0x00007ff1941d6800 nid=0x49c8 runnable [0x00007ff1986e7000] java.lang.Thread.State: RUNNABLE at com.example.demo.service.TestService.testMethod(TestService.java:16) at sun.reflect.GeneratedMethodAccessor66.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) "Thread-2" #120 prio=5 os_prio=0 tid=0x00007ff1941d8800 nid=0x49c9 waiting on condition [0x00007ff1985e6000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007926d08d0> (a com.example.demo.entity.TestEntity) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039) at com.example.demo.service.TestService.testMethod(TestService.java:24) at sun.reflect.GeneratedMethodAccessor71.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
五、总结
通过本文的介绍,我们了解了jstack日志分析的流程、常用工具和分析方法。在实际的开发中,我们可以根据具体的问题选择不同的工具进行分析,可以更快地解决问题,提高开发效率。