当前位置:Java -> Java线程转储分析
线程转储 分析是分析基于Java的应用程序性能瓶颈的传统方法。在现代社会,我们有APM工具可以提供各种度量和屏幕以深入挖掘和识别性能问题,甚至在代码级别。但是对于一些性能问题或场合,线程转储分析仍然是识别瓶颈的最佳方式。
为了分析任何性能问题,最好连续进行一系列线程转储,并且以1到2秒的时间间隔。每次进行10-15次线程转储,每个间隔1-2秒,有助于分析那些卡住或在线程转储中执行相同代码的线程。
可以在以下情况下进行线程转储:
有时,应用程序服务器也会自动生成线程转储。例如,WebSphere应用程序服务器在发生OutOfMemoryError
情况时会生成线程转储,这有助于分析该时刻的线程的各种状态。
对于情况#1和#2,应该关注处于阻塞,停放/等待和可运行状态的线程。对于情况#3,应该关注处于可运行状态的线程。一些无限循环执行的线程可能导致CPU使用率过高,查看可运行状态可能有助于找到问题所在。对于情况#4,应该关注处于可运行和停放/等待线程状态的线程。在所有情况下,忽略处于停放或定时等待状态的线程,这些线程在等待任务/请求执行。
使用工具分析线程转储将提供有关线程及其状态的许多统计信息。然而,有时它可能无法揭示系统中的真正瓶颈。最好始终手动阅读线程转储,并借助诸如Notepad++等工具进行分析。如果有许多线程转储要分析,可以使用IBM线程转储分析器。它可以帮助组织性地查看线程转储以加快分析过程。虽然它不会提供许多在线分析工具那样复杂的统计信息,但它有助于更好地可视化线程转储,提供查看由于其他线程而被阻塞的线程,并帮助比较线程转储。
在分析线程转储时,重要的是要知道线程转储是为哪个应用程序服务器提取的,因为这将有助于集中分析正确的线程。例如,如果在WebSphere应用程序服务器上提取了线程转储,那么“Web Container”线程池应该是分析的第一地,因为这是WebSphere应用程序服务器的入口点,它将开始处理到达其的请求。
通常,线程转储中会有两种类型的线程。一类线程与应用程序相关,并帮助执行应用程序代码。另一类线程执行各种操作,例如从网络读取/写入、心跳检查,以及包括JVM内部(如GC等)在内的各种其它操作。根据问题的不同,应该关注这两种线程类别。大多数情况下,应用程序代码可能是性能瓶颈的罪魁祸首;因此,应该更关注应用程序线程。
线程转储显示应用程序中各种线程池。在WebSphere应用程序服务器中,名称为“Web Container: <id>”的线程属于WebSphere线程池。对这些线程的数量进行计数应等于定义的线程池大小。如果超出这一数量,表示线程池存在泄漏。需要验证线程转储中不同线程池的大小。
ForkJoinPool
是Java CompletableFuture
用于异步运行任务的另一个线程池。如果该线程池中有太多异步任务,则需要增加线程池的大小,或创建一个具有更大大小的新线程池。否则,这个ForkJoinPool
将成为异步任务执行的瓶颈。
如果应用程序使用Java Executor框架创建线程池,则默认名称为“pool-<id1>-thread-<id2>
”的线程将分配给这些线程。这里的“id1”表示线程池编号,“id2”表示线程池中的线程数。有时,如果开发人员每次都通过Executor框架创建新线程池但没有关闭它们,那么每次都会创建不同的线程池,线程数量会增加。如果这些线程没有在积极执行某些任务,则可能不会造成问题,但当达到最大线程创建数量时会导致OutOfMemoryError
无法创建新线程。在分析任何线程转储时,查看不同线程池并确保它们都在定义/期望的限制内总是一个好习惯。
从线程转储的堆栈跟踪中关注应用程序方法可以帮助分析应用程序代码中的问题。如果应用程序中存在同步代码或块,则应用程序线程将等待获取对象的锁来进入特定代码/块的执行。这将很昂贵,因为只允许一个线程进入代码执行,导致其他线程等待。在线程转储中可以看到线程等待获取对象锁。如果同步不是必要的,则可以修改代码以避免同步。
线程转储包含有关
推荐阅读: 互联网及私企提前批/秋招信息汇总(更新)
本文链接: Java线程转储分析