当前位置: 首页 > 科技观察

JVM:如何分析线程栈

时间:2023-03-13 14:26:44 科技观察

本文将教大家如何分析JVM线程栈,以及如何从栈信息中找到问题的根源。在我看来,线程堆栈分析技术是JavaEE产品支持工程师必须掌握的技术。线程栈中存储的信息通常远远超出你的想象,我们可以在工作中很好地利用这些信息。我的目标是分享我过去十几年在线程分析方面积累的知识和经验。这些知识和经验是在深入分析各种版本的JVM和各个厂商的JVM供应商中得到的。在这个过程中,我也总结了大量的通用问题模板。那么,准备好了吗,现在就将这篇文章添加为书签,我将在接下来的几周内为您带来这一系列的专题文章。还等什么,赶快把这份线程分析培训计划分享给您的同事朋友吧。听起来不错,我真的应该提高我的线程堆栈分析技能……但是我从哪里开始呢?我的建议是跟随我完成这个线程分析培训计划。以下是我们将在培训中介绍的内容。同时,我会把我处理过的实际案例分享给大家,与大家一起学习和理解。1)线程栈概述及基础知识2)线程栈生成原理及相关工具3)不同JVM线程栈(SunHotSpot、IBMJRE、OracalJRockit)格式差异4)线程栈日志介绍及分析方法5)线程堆栈分析及相关技术6)常见问题模板(线程竞争、死锁、IO调用挂起、垃圾回收/OutOfMemoryError问题、死循环等)7)线程堆栈问题实例分析希望本系列培训能真正帮到你你,所以请继续关注每周的文章更新。但是在学习过程中遇到疑问或者看不懂文章内容怎么办?别担心,就当我是你的导师吧。有什么关于线程栈的问题可以找我咨询(前提是问题不是太low)。请随时选择以下方式与我取得联系:1)直接在本文下方发表评论(不好意思可以匿名)2)将你的线程栈数据提交到根本原因分析论坛3)Email我在@phcharbonneau@hotmail.com可以帮我分析一下我们产品遇到的问题吗?当然,如果你愿意,你可以通过电子邮件或根本原因分析论坛将你的堆栈字段数据发送给我。处理实际问题是学习和提高技能的王道。我真诚地希望您会喜欢这次培训。所以我会尽我所能为大家提供优质的素材,解答大家的各种问题。在介绍线程栈分析技术和问题模型之前,先给大家讲一下基础知识。所以在这篇文章中,我会先介绍最基础的内容,让大家更好的理解JVM、中间件和JavaEE容器之间的交互。JavaVM概述Java虚拟机是JavaEE平台的基础。它是部署和运行中间件和应用程序的地方。JVM为中间件软件和您的Java/JavaEE程序提供以下内容:-(以二进制形式)Java/JavaEE程序执行环境-一些程序功能和工具(IO基础结构、数据结构、线程管理、安全、监控,等等)–动态内存分配和垃圾回收管理你的JVM可以驻留在许多操作系统上(Solaris,AIX,Windows等)并且可以根据你的物理服务器进行配置,你可以在上面安装1到多个JVM进程每个物理/虚拟服务器。JVM和中间件之间的交互??下图显示了JVM、中间件和应用程序之间的高级交互模型。JVM、中间件和应用程序之间的一些简单典型的交互如图所示。如您所见,标准JavaEE应用程序的线程分配是在中间件核心和JVM之间完成的。(当然也有例外,应用程序可以直接调用API创建线程,这种做法并不常见,使用时要特别注意。)同时请注意,有些线程是由JVM内部管理的,典型的一个例子是垃圾收集线程,JVM内部使用它来进行并行垃圾收集处理。由于大多数线程分配是由JavaEE容器完成的,因此能够理解和识别线程堆栈跟踪并能够从线程堆栈数据中识别它对您来说很重要。这使您可以快速了解JavaEE容器正在执行什么类型的请求。从线程转储堆栈分析的角度,您将能够了解从JVM看到的线程池之间的区别并识别请求的类型。最后一节将概述什么是HotSopVM的JVM线程堆栈,以及您将遇到的各种线程。IBMVM线程堆栈格式的详细信息将在第4节中提供给您。请注意,您可以从根本原因分析论坛获取本文的线程堆栈示例。JVM线程栈——它是什么?JVM线程堆栈是给定时间的快照,它为您提供了所有创建的Java线程的完整列表。每个发现的Java线程都会为您提供以下信息:–线程的名称;通常被中间件供应商用来标识线程的ID,通常带有分配的线程池的名称和状态(运行、阻塞等)——线程类型和优先级,例如:daemonprio=3**中间件程序通常创建它们的线程作为守护进程,这意味着这些线程在后台运行;用户提供服务,例如:给你的JavaEE应用**-Java线程ID,例如:tid=0x000000011e52a800**这是通过java.lang.Thread.getId()得到的Java线程ID,常用于增加长整型1..n**实现-nativethreadID,eg:nid=0x251c**,原因是nativethreadID可以让你从操作系统的相关信息,例如大部分CPU使用时间。**–Java线程状态和详细信息,例如:waitingformonitorentry[0xfffffffea5afb000]java.lang.Thread.State:BLOCKED(onobjectmonitor)**可以快速了解线程状态和当前阻塞的可能原因**-Java线程堆栈跟踪;这是迄今为止您可以从线程堆栈中找到的最重要的数据。这这也是您花费最多分析时间的地方,因为Java堆栈跟踪提供了您将在稍后的实践会话中学习的许多类型问题的根本原因所需的90%的信息-Java堆内存分解;从HotSpotVM1.6版本开始,可以在线程栈的末尾看到HotSpot的内存使用情况,比如Java的堆内存(YoungGen、OldGen)&PermGen空间。在分析频繁GC导致的问题时,此信息很有用。您可以使用已知的线程数据或模式来进行快速修复。HeapPSYoungGentotal466944K,used178734K[0xffffffff45c00000,0xffffffff70800000,0xffffffff70800000)edenspace233472K,76%used[0xffffffff45c00000,0xffffffff50ab7c50,0xffffffff54000000)fromspace233472K,0%used[0xffffffff62400000,0xffffffff62400000,0xffffffff70800000)tospace233472K,0%used[0xffffffff54000000,0xffffffff54000000,0xffffffff62400000)PSOldGentotal1400832K,used1400831K[0xfffffffef0400000,0xffffffff45c00000,0xffffffff45c00000)objectspace1400832K,99%used[0xfffffffef0400000,0xffffffff45bfffb8,0xffffffff45c00000)PSPermGentotal262144K,used248475K[0xfffffffed0400000,0xfffffffee0400000,0xfffffffef0400000)objectspace262144K,94%used[0xfffffffed0400000,0xfffffffedf6a6f08,0xfffffffee0400000)线程堆栈信息大拆解为了让大家为了更好地理解,我为您提供了以下图片。在这张图中,对HotSpotVM上的线程栈信息和线程池进行了详细的拆解,如下图所示:从上图可以看出,线程栈是由很多不同的部分组成的。这些信息对于问题分析很重要,但是不同问题模式的分析会用到不同的部分(问题模式将在后面的文章中进行模拟和演示。)现在通过这个分析例子,详细解释一下HoteSpot上线程栈信息的各个组成部分:#Fullthreaddump标识符“Fullthreaddump”是一个全局唯一的关键字,你可以在中间件和单机中使用它在Java版本的线程堆栈信息的输出日志中找到(例如UNIX下使用:kill-3)。这是线程堆栈快照的开始。FullthreaddumpJavaHotSpot(TM)64-BitServerVM(20.0-b11mixedmode):#JavaEE中间件、第三方和自定义应用软件中的Threads这部分是整个线程栈的核心部分,通常分析时间最多。堆栈中的线程数取决于您使用的中间件、第三方库(可能有单独的线程)和您的应用程序(如果您创建自定义线程,这通常不是一个好的做法)。在我们的示例线程堆栈中,WebLogic是我们使用的中间件。从Weblogic9.2开始,将使用由“'weblogic.kernel.Default(自调优)”唯一标识的自管理线程池“[STANDBY]ExecuteThread:'414'forqueue:'weblogic.kernel.Default(self-调整)'"daemonprio=3tid=0x000000010916a800nid=0x2613inObject.wait()[0xffffffffe9edff000]java.lang.Thread.State:WAITING(onobjectmonitor)atjava.lang.Object.wait(NativeMethod)-waitingon<0xfffffff27d44logic.de0>(.ExecuteThread)atjava.lang.Object.wait(Object.java:485)atweblogic.work.ExecuteThread.waitForRequest(ExecuteThread.java:160)-locked<0xffffffff27d44de0>(aweblogic.work.ExecuteThread)atweblogic.work.ExecuteThread.run(ExecuteThread.java:181)#HotSpotVM线程这是HotspotVM管理的内部线程,用于执行内部native操作。通常你不需要太担心这个,除非你发现CPU使用率很高(通过相关的线程堆栈和prstat或本机线程Id)。在执行并行GC时(如今在使用多个物理内核的环境中很常见),默认创建的HotSpotVM或每个JVM管理一个具有特定标识符的GC线程。这些GC线程允许VM以并行方式执行其循环性GC清理,这将导致GC时间的整体减少;同时,代价是CPU使用时间会增加。"GCtaskthread#0(ParallelGC)"prio=3tid=0x0000000100120000nid=0x3runnable"GCtaskthread#1(ParallelGC)"prio=3tid=0x0000000100131000nid=0x4runnable……………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………当你遇到与GC相关的问题时,比如过度GC、内存泄漏等,你将可以通过操作系统或Java线程关联这些线程的nativeId值来发现任何高占用CPI时间的问题。在以后的文章中,您将学习如何识别和诊断此类问题。#JNI全局引用计数JNI(Java本机接口)全局引用基本上是从本机代码到Java垃圾收集器管理的Java对象的对象引用。它的作用是防止对本机代码仍在使用但技术上不再是Java代码中的“活动”引用的对象进行垃圾回收。密切关注JNI引用以检测与JNI相关的泄漏也很重要。如果你的程序直接使用JNI,或者监听器之类的第三方工具,很容易造成局部内存泄漏。JNIglobalreferences:1925#Javastackusageview此数据被添加回JDK1.6,为您提供Hotspot堆栈的视图简短而快速的视图。我在处理CPU使用率高的GC相关问题时发现它非常有用,你可以在单个快照中同时看到线程堆栈和Java堆信息,让你可以解决(或排除)特定Java中的任何关键点堆内存空间。正如您在我们的示例线程堆栈中所看到的,Java的堆OldGen超过了最大值!HeapPSYoungGentotal466944K,used178734K[0xffffffff45c00000,0xffffffff70800000,0xffffffff70800000)edenspace233472K,76%used[0xffffffff45c00000,0xffffffff50ab7c50,0xffffffff54000000)fromspace233472K,0%used[0xffffffff62400000,0xffffffff62400000,0xffffffff70800000)tospace233472K,0%used[0xffffffff54000000,0xffffffff54000000,0xffffffff62400000)PSOldGentotal1400832K,used1400831K[0xffffffffef0400000,0xfffffff45c00000,0xfffffff45c00000)objectspace1400832K,99%used[0xfffffffef0400000,0xffffffff45bfffb8,0xffffffff45c00000)PSPermGentotal262144K,used248475K[0xfffffffed0400000,0xfffffffee0400000,0xfffffffef0400000)objectspace262144K,94%used[0xfffffffed0400000,0xfffffffedf6a6f08,0xfffffffee0400000)我希望这篇文章能对你理解HotspotVM线程堆栈的基本信息很有帮助下一篇文章将为您提供IBMVM上线程堆栈的概述和分析。请随时发表对本文的意见或问题。引用:如何分析线程堆栈-第1部分,如何分析线程堆栈--第2部分和如何分析线程转储-第3部分来自我们的JCG合作者HuguesCharbonneau在JavaEE支持模式和Java教程博客上。英文原文:JVM:HowtoanalyzeThreadDump翻译链接:http://www.oschina.net/translate/jvm-how-to-analyze-thread-dump