为了使您能够从线程转储中快速识别问题模式,首先需要了解如何读取线程堆栈跟踪以及如何正确获取“故事”。 这意味着,如果我要您告诉我#38线程在做什么? 您应该能够准确回答; 包括“线程堆栈跟踪”是否显示正常(正常)与挂起状态。
再谈Java堆栈跟踪
你们中的大多数人都熟悉Java堆栈跟踪。 当抛出Java异常时,这是我们从服务器和应用程序日志文件中找到的典型数据。 在这种情况下,Java堆栈跟踪为我们提供了触发Java异常的Thread的代码执行路径,例如java.lang.NoClassDefFoundError,java.lang.NullPpointerException等。此类代码执行路径使我们可以查看不同的层最终导致Java异常的代码。
必须始终从下至上读取Java堆栈跟踪:
- 底部的行将显示请求的始发者,例如Java / Java EE容器Thread。
- 堆栈跟踪顶部的第一行将向您显示触发了最后一个Exception的Java类。
让我们通过一个简单的示例来完成此过程。 我们创建了一个示例Java程序,只需执行一些Class方法调用并抛出Exception。 生成的程序输出如下:
JavaStrackTraceSimulator
Author: Pierre-Hugues Charbonneau
http://javaeesupportpatterns.blogspot.comException in thread "main" java.lang.IllegalArgumentException:at org.ph.javaee.training.td.Class2.call(Class2.java:12)at org.ph.javaee.training.td.Class1.call(Class1.java:14)at org.ph.javaee.training.td.JavaSTSimulator.main(JavaSTSimulator.java:20)
- 调用Java程序JavaSTSimulator(通过“主”线程)
- 然后,模拟器从Class1调用方法call()
- 然后,Class1方法call()调用Class2方法call()
- Class2方法call()引发Java异常:java.lang.IllegalArgumentException
- 然后,在日志/标准输出中显示Java异常
如您所见,导致此异常的代码执行路径始终从下至上显示。
上面的分析过程对于任何Java程序员都应该是众所周知的。 接下来,您将看到线程转储线程堆栈跟踪分析过程与上述Java堆栈跟踪分析非常相似。
线程转储:线程堆栈跟踪分析
从JVM生成的线程转储为您提供了整个JVM进程中所有“创建的”线程的代码级执行快照。 创建线程并不意味着所有这些线程实际上都在做某事。 在从Java EE容器JVM生成的典型线程转储快照中:
- 一些线程可能正在执行原始计算任务,例如XML解析,IO /磁盘访问等。
- 一些线程可能正在等待一些阻塞的IO调用,例如远程Web服务调用,DB / JDBC查询等。
- 那时某些线程可能涉及垃圾回收,例如GC线程
- 一些线程将等待一些工作要做(不做任何工作的线程通常进入wait()状态)
- 一些线程可能正在等待其他一些线程完成工作,例如,一些线程正在等待获取某些对象上的监视器锁定(同步块{})
在下一篇文章中,我将返回上面的更多图表,但现在让我们集中讨论堆栈跟踪分析过程。 您的下一个任务是能够尽您所能读取线程堆栈跟踪并了解它在做什么。
线程堆栈跟踪为您提供了其当前执行的快照。 第一行通常包含线程的本机信息,例如其名称,状态,地址等。当前执行堆栈跟踪必须自下而上读取。 请遵循以下分析过程。 您从线程转储分析中获得的经验越多,您就能越快地读取并快速识别每个线程执行的工作:
- 从底部开始读取线程堆栈跟踪
- 首先,确定发起者(Java EE容器线程,自定义线程,GC线程,JVM内部线程,独立的Java程序“主”线程等)。
- 下一步是确定线程正在执行的请求的类型(WebApp,Web Service,JMS,远程EJB(RMI),内部Java EE容器等)。
- 下一步是从执行堆栈中识别出您所涉及的应用程序模块的形式,例如,线程正在尝试执行的实际核心工作。 分析的复杂性将取决于中间件环境和应用程序的抽象层
- 下一步是查看第一行之前的最后〜10-20行。 标识线程所涉及的协议或工作,例如HTTP调用,套接字通信,JDBC或原始计算任务,例如磁盘访问,类加载等。
- 下一步是看第一行。 第一行通常告诉LOT处于Thread状态,因为它是您拍摄快照时执行的当前代码
- 最后两个步骤的组合将为您提供信息的核心,以总结线程所涉及的工作和/或悬挂条件
现在,使用从JBoss 5生产环境捕获的Thread Dump Thread堆栈跟踪的真实示例,在下面直观地查看上述步骤。 在此示例中,许多线程在创建新的JAX-WS Service实例时都显示了类似的问题,即IO过多。
如您所见,最后10行和第一行将告诉我们线程所涉及的挂起或缓慢状态(如果有)。 底部的几行将为我们提供发起者和请求类型的详细信息。
我希望本文能帮助您了解正确的线程堆栈跟踪分析的重要性。 当我们在以后的文章中介绍最常见的线程转储问题模式时,我将带回更多的线程堆栈跟踪示例。 现在,下一篇文章将教您如何在逻辑孤岛中分解线程转储线程,并提出潜在的根本原因“可疑”列表。
参考: 如何分析线程转储–第5部分:来自JCG合作伙伴 Pierre-Hugues Charbonneau的Java EE支持模式和Java教程博客中的线程堆栈跟踪 。
翻译自: https://www.javacodegeeks.com/2012/07/how-to-analyze-thread-dump-thread-stack.html