Java线程dump分析
weblogic线程快照threaddump分析
Java 的线程线程是指能独立于程序的其它部分运行的执行单元。
JAVA语言能够很好的实现多线程的程序。
我们在调试程序,或者在开发后期需要做性能调优的时候,往往也需要了解当前程序正在运行的线程的状态,正在执行的操作,从而分析系统可能存在的问题。
在阅读本文之间,应对Java线程的编程原理,同步机制有一定了解.产生JAVA线程dumpJAVA 的线程DUMP,就象当前JAVA进程的一个快照,打印出所有线程的状态和调用堆栈,以及Monitor的状态。
在不同的操作系统下,产生线程DUMP的方式是不同的。
在启动程序的控制台里敲:Ctrl - Break,线程的dump会产生在标准输出中(缺省标准输出就是控制台,如果对输出进行了重定向,则要查看输出文件)。
在unix,linux 和MacOS 环境中,在控制台中敲:Ctrl-\,或者,用“kill -3 <pid>” ,或者“kill –QUIT <pid>”。
Pid是用所关注的JAVA进程号,您可以用“ps -ef | grep j ava” 找到,或者使用JDK 5.0中的“jps -v” 命令获得。
在各个操作系统平台,都可以用JDK 5.0工具包中的jstack <pid>这里要注意的是:1. 不同的JAVA虚机的线程DUMP的创建方法和文件格式是不一样的,不同的JVM版本,dump信息也有差别。
本文中,只以SUN的hotspot JVM 5.0_06 为例。
2. 在实际运行中,往往一次dump的信息,还不足以确认问题。
建议产生三次dump信息,如果每次dump都指向同一个问题,我们才确定问题的典型性。
线程分析:1. JVM 线程在线程中,有一些JVM内部的后台线程,来执行譬如垃圾回收,或者低内存的检测等等任务,这些线程往往在JVM初始化的时候就存在,如下所示:"Low Memory Detector" daemon prio=10 tid=0x081465f8 nid=0x7 runnable [0x00000000..0x00000000]"CompilerThread0" daemon prio=10 tid=0x08143c58 nid=0x6 waiting on condition [0x00000000..0xfb5fd798]"Signal Dispatcher" daemon prio=10 tid=0x08142f08 nid=0x5 waiting on condition [0x00000000..0x00000000]"Finalizer" daemon prio=10 tid=0x08137ca0 nid=0x4 in Object.wait() [0xfbeed000..0xfbeeddb8]at ng.Object.wait(Native Method)- waiting on <0xef600848> (a ng.ref.ReferenceQueue$Lock)at ng.ref.ReferenceQueue.remove(ReferenceQueue.java:116)- locked <0xef600848> (a ng.ref.ReferenceQueue$Lock)at ng.ref.ReferenceQueue.remove(ReferenceQueue.java:132)at ng.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)"Reference Handler" daemon prio=10 tid=0x081370f0 nid=0x3 in Object.wait() [0xfbf4a000..0xfbf4aa38]at ng.Object.wait(Native Method)- waiting on <0xef600758> (a ng.ref.Reference$Lock)at ng.Object.wait(Object.java:474)at ng.ref.Reference$ReferenceHandler.run(Reference.java:116)- locked <0xef600758> (a ng.ref.Reference$Lock)"VM Thread" prio=10 tid=0x08134878 nid=0x2 runnable"VM Periodic Task Thread" prio=10 tid=0x08147768 nid=0x8 waiting on condition 我们更多的是要观察用户级别的线程,如下所示:"Thread-1" prio=10 tid=0x08223860 nid=0xa waiting on condition [0xef47a000..0xef47ac38]at ng.Thread.sleep(Native Method)at testthread.MySleepingThread.method2(MySleepingThread.java:53)- locked <0xef63d600> (a testthread.MySleepingThread)at testthread.MySleepingThread.run(MySleepingThread.java:35)at ng.Thread.run(Thread.java:595)我们能看到:线程的状态:waiting on condition线程的调用栈线程的当前锁住的资源:<0xef63d600> 这些信息对我们随后的分析都有用处。
jvm dump参数
JVM Dump参数什么是JVM Dump?JVM(Java虚拟机)Dump是指在Java应用程序运行时,将JVM的内部状态转储到文件中的过程。
这些转储文件包含了应用程序在运行时的堆栈跟踪、线程信息、对象实例等重要信息。
通过分析这些转储文件,我们可以了解应用程序在发生故障或异常时的状态,有助于定位和解决问题。
为什么需要JVM Dump?在调试和解决Java应用程序中的问题时,JVM Dump起着关键作用。
它可以提供以下信息:1.内存快照:通过JVM Dump,可以获取应用程序在某个时间点的内存快照。
这对于分析内存泄漏、内存溢出等问题非常有帮助。
2.线程信息:JVM Dump中包含了所有线程的堆栈跟踪和状态信息。
这对于查找死锁、线程阻塞等问题非常有帮助。
3.对象实例:通过JVM Dump,可以获取当前堆中存在的所有对象实例以及它们的引用关系。
这对于分析对象创建和销毁情况、查找对象泄漏等问题非常有帮助。
4.GC信息:JVM Dump中还包含了GC(垃圾回收)的详细信息,包括GC算法、GC线程状态、堆内存使用情况等。
这对于分析GC性能和调优非常有帮助。
综上所述,JVM Dump提供了详尽的应用程序状态信息,帮助开发人员快速定位和解决问题,提高应用程序的稳定性和性能。
如何生成JVM Dump?在Java应用程序中,可以通过以下方式生成JVM Dump:1.使用命令行工具:可以使用jmap命令生成JVM Dump。
例如,执行以下命令将生成一个名为dump.bin的转储文件:jmap -dump:format=b,file=dump.bin <pid>其中,<pid>是Java进程的进程ID。
2.使用JDK工具:JDK提供了一些图形化工具,如jvisualvm、Java MissionControl等,可以通过这些工具生成JVM Dump。
在这些工具中,通常有一个按钮或菜单项可以直接生成转储文件。
Java中抓取ThreadDumps的方式汇总
Java中抓取ThreadDumps的⽅式汇总1. jstackjstack 是⼀个抓取 thread dump ⽂件的有效的命令⾏⼯具,它位于 JDK ⽬录⾥的 bin ⽂件夹下(JDK_HOME\bin),以下是抓取 dump ⽂件的命令:jstack -l <pid> > <file-path>说明:pid: Java 应⽤的进程 id ,也就是需要抓取 dump ⽂件的应⽤进程 id。
file-path:保存 dump ⽂件的路径。
⽰例:jstack -l 37320 > /opt/tmp/threadDump.txt上⾯的例⼦演⽰了⽤ jstack ⽣成 dump ⽂件到 /opt/tmp/threadDump.txt ⽬录下。
从 Java5 开始,jstack 被包含进了 jdk 当中,如果你使⽤⽼版本的 jdk,要考虑使⽤其他⽅式。
2. Kill -3处于安全⽅⾯的考虑,有⼀部分⽣产环境的机器只包含 JRE 环境,因此就不能使⽤ jstack ⼯具了,在这种情况下,我们可以使⽤ kill -3 的⽅式:kill -3 <pid>说明:pid: Java 应⽤的进程 id ,也就是需要抓取 dump ⽂件的应⽤进程 id 。
⽰例:kill -3 37320当使⽤ kill -3 ⽣成 dump ⽂件时,dump ⽂件会被输出到标准错误流。
假如你的应⽤运⾏在 tomcat 上,dump 内容将被发送到<TOMCAT_HOME>/logs/catalina.out ⽂件⾥。
3. JVisualVMJava VisualVM 是⼀个可以提供 JVM 信息的图形界⾯⼯具。
它位于 JDK_HOME\bin\jvisualvm.exe ⽂件⾥。
从 JDK6 Update7 开始,它被包含进 JDK ⾥。
运⾏ jvisualvm,在左侧⾯板中(如下图所⽰),列出了运⾏的 JVM 信息,这个⼯具可以从本地或者远程运⾏的 JVM ⾥抓取 dump ⽂件。
jvm dump参数
JVM Dump参数什么是JVM Dump?在Java虚拟机(JVM)中,Dump是指将内存中的数据转储到磁盘上的一个过程。
JVM Dump是一种用于分析和调试Java应用程序的重要工具。
它可以帮助开发人员了解应用程序在运行时的状态,包括线程信息、对象实例、堆栈跟踪等。
JVM Dump参数的作用JVM Dump参数允许开发人员在特定条件下生成Dump文件,以便进行后续分析。
通过使用这些参数,我们可以捕获应用程序在出现问题时的内存快照,从而更好地理解问题所在并进行故障排除。
常见的JVM Dump参数以下是常见的JVM Dump参数及其作用:1.-XX:+HeapDumpOnOutOfMemoryError:当发生OutOfMemoryError错误时,自动生成Heap Dump文件。
这对于分析内存泄漏问题非常有帮助。
2.-XX:+PrintGCDetails:打印详细的垃圾回收信息,包括GC事件、堆大小等。
这对于监视和调优垃圾回收行为非常有帮助。
3.-XX:+PrintGCDateStamps:打印GC事件发生的时间戳。
这对于跟踪GC事件和性能分析很有帮助。
4.-XX:+PrintHeapAtGC:在每次垃圾回收之后打印堆的详细信息。
这对于分析堆中对象的分配和回收情况非常有帮助。
5.-XX:+PrintClassHistogram:打印当前加载的类的直方图信息,包括实例数和内存占用量。
这对于了解应用程序中对象的使用情况非常有帮助。
6.-XX:+PrintVMOptions:打印JVM启动时所有的参数设置。
这对于检查JVM参数是否正确配置很有帮助。
7.-XX:+PrintCommandLineFlags:打印JVM运行时通过命令行设置的标志。
这对于检查JVM运行时参数是否正确生效很有帮助。
8.-XX:OnError=“;”:当JVM发生致命错误时,执行指定的命令。
这对于处理严重故障时采取自定义操作很有帮助。
Java内存泄漏分析系列之一:使用jstack定位线程堆栈信息
Java内存泄漏分析系列之⼀:使⽤jstack定位线程堆栈信息原⽂地址:前⼀段时间上线的系统升级之后,出现了严重的⾼CPU的问题,于是开始了⼀系列的优化处理之中,现在将这个过程做成⼀个系列的⽂章。
基本概念在对Java内存泄漏进⾏分析的时候,需要对jvm运⾏期间的内存占⽤、线程执⾏等情况进⾏记录的dump⽂件,常⽤的主要有thread dump和heap dump。
thread dump 主要记录JVM在某⼀时刻各个线程执⾏的情况,以栈的形式显⽰,是⼀个⽂本⽂件。
通过对thread dump⽂件可以分析出程序的问题出现在什么地⽅,从⽽定位具体的代码然后进⾏修正。
thread dump需要结合占⽤系统资源的线程id进⾏分析才有意义。
heap dump 主要记录了在某⼀时刻JVM堆中对象使⽤的情况,即某个时刻JVM堆的快照,是⼀个⼆进制⽂件,主要⽤于分析哪些对象占⽤了太对的堆空间,从⽽发现导致内存泄漏的对象。
上⾯两种dump⽂件都具有实时性,因此需要在服务器出现问题的时候⽣成,并且多⽣成⼏个⽂件,⽅便进⾏对⽐分析。
下⾯我们先来说⼀下如何⽣成 thread dump。
使⽤⽣成thread dump当服务器出现⾼CPU的时候,⾸先执⾏top -c命令动态显⽰进程及占⽤资源的排⾏,如下图:top后⾯的参数-c可以显⽰进程详细的信息。
top命令执⾏的时候还可以执⾏⼀些快捷键:1对于多核服务器,可以显⽰各个CPU占⽤资源的情况shift+h显⽰所有的线程信息shift+w将当前top命令的设置保存到~/.toprc⽂件中,这样不⽤每次都执⾏快捷键了以上图为例,pid为1503的进程占⽤了⼤量的CPU资源,接下来需要将占⽤CPU最⾼进程中的线程打印出来,可以⽤top -bn1 -H -p <pid>命令,执⾏结果如下:上⾯-bn1参数的含义是只输出⼀次结果,⽽不是显⽰⼀个动态的结果。
我个⼈请喜欢⽤ps -mp <pid> -o THREAD,tid,time | sort -k2r命令查看,后⾯的sort参数根据线程占⽤的cpu⽐例进⾏排序,结果如下:接下来我们清楚今天的主⾓jstack,这是⼀个在JDK5开始提供的内置⼯具,可以打印指定进程中线程运⾏的状态,包括线程数量、是否存在死锁、资源竞争情况和线程的状态等等。
Dump文件分析(转发)
Dump⽂件分析(转发)原⽂:本⽂主要介绍Dump⽂件结构,理解Dump⽂件对于分析线程⾼占⽤、死锁、内存溢出等⾼级问题有⾮常重要的指导意义。
什么是Dump⽂件Dump⽂件是进程的内存镜像。
可以把程序的执⾏状态通过调试器保存到dump⽂件中。
Dump⽂件是⽤来给程序编写⼈员调试程序⽤的,这种⽂件必须⽤专⽤⼯具软件打开。
如何⽣成Dump⽂件使⽤命令:jstack pid可以查看到当前运⾏的java进程的dump信息。
Dump⽂件结构⾸先浏览⼀下dump⽂件的⽂本内容:Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.77-b03 mixed mode):"Attach Listener" #37 daemon prio=9 os_prio=0 tid=0x00007f87b42b7000 nid=0x680f waiting on condition [0x0000000000000000]ng.Thread.State: RUNNABLE"Druid-ConnectionPool-Destory-331358539" #36 daemon prio=5 os_prio=0 tid=0x00007f87a4278800 nid=0x67e4 waiting on condition [0x00007f87b8dce000] ng.Thread.State: TIMED_WAITING (sleeping)at ng.Thread.sleep(Native Method)at com.alibaba.druid.pool.DruidDataSource$DestroyConnectionThread.run(DruidDataSource.java:1724)"Druid-ConnectionPool-Create-331358539" #35 daemon prio=5 os_prio=0 tid=0x00007f87a4022000 nid=0x67e3 waiting on condition [0x00007f87ce86a000] ng.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000000b3804848> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:1629)"Abandoned connection cleanup thread" #31 daemon prio=5 os_prio=0 tid=0x00007f87e0d91800 nid=0x672b in Object.wait() [0x00007f87cd2c2000]ng.Thread.State: TIMED_WAITING (on object monitor)at ng.Object.wait(Native Method)at ng.ref.ReferenceQueue.remove(ReferenceQueue.java:143)- locked <0x00000000b422d1e8> (a ng.ref.ReferenceQueue$Lock)at com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:43)"DestroyJavaVM" #30 prio=5 os_prio=0 tid=0x00007f87e0008800 nid=0x670b waiting on condition [0x0000000000000000]ng.Thread.State: RUNNABLE"http-nio-8081-AsyncTimeout" #28 daemon prio=5 os_prio=0 tid=0x00007f87e016e800 nid=0x6727 waiting on condition [0x00007f87b94cf000]ng.Thread.State: TIMED_WAITING (sleeping)at ng.Thread.sleep(Native Method)at org.apache.coyote.AbstractProtocol$AsyncTimeout.run(AbstractProtocol.java:1211)at ng.Thread.run(Thread.java:745)"http-nio-8081-Acceptor-0" #27 daemon prio=5 os_prio=0 tid=0x00007f87e0166000 nid=0x6726 runnable [0x00007f87b95d0000]ng.Thread.State: RUNNABLEat sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)- locked <0x00000000b410d480> (a ng.Object)at .NioEndpoint$Acceptor.run(NioEndpoint.java:455)at ng.Thread.run(Thread.java:745)"http-nio-8081-ClientPoller-0" #26 daemon prio=5 os_prio=0 tid=0x00007f87e0292800 nid=0x6725 runnable [0x00007f87b96d1000]ng.Thread.State: RUNNABLEat sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)- locked <0x00000000b410d6c0> (a sun.nio.ch.Util$2)- locked <0x00000000b410d6b0> (a java.util.Collections$UnmodifiableSet)- locked <0x00000000b410d668> (a sun.nio.ch.EPollSelectorImpl)at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)at .NioEndpoint$Poller.run(NioEndpoint.java:793)at ng.Thread.run(Thread.java:745)"http-nio-8081-exec-10" #25 daemon prio=5 os_prio=0 tid=0x00007f87e028c000 nid=0x6724 waiting on condition [0x00007f87b97d2000]ng.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000000b410d898> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:103)at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:31)at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at ng.Thread.run(Thread.java:745)其中每个空⾏⽤于分隔⼀个线程,每个线程的信息是以堆栈信息的⽅式展开,显⽰了⽬前正在调⽤的⽅法以及所在的代码⾏。
java内存dump文件导出与查看
请求出错错误代码400请尝试刷新页面重试
java内存 dump文件ห้องสมุดไป่ตู้出与查看
生成dump文件的命令: jmap -dump:format=b,file=20170307.dump 16048 file后面的是自定义的文件名,最后的数字是进程的pid
使用jvisualvm来分析dump文件: jvisualvm是JDK自带的Java性能分析工具,在JDK的bin目录下,文件名就叫jvisualvm.exe。 jvisualvm可以监控本地、远程的java进程,实时查看进程的cpu、堆、线程等参数,对java进程生成dump文件,并对dump文件进行分析。 像我这种从服务器上dump下来文件也可以直接扔给jvisualvm来分析。 使用方式:直接双击打开jvisualvm.exe,点击文件->装入,在文件类型那一栏选择堆,选择要分析的dump文件,打开。
3,heapdump和threaddump分析
3,heapdump和threaddump分析⼀:heap dump1、heapdump:记录内存信息的,heap dump⽂件是⼀个⼆进制⽂件,它保存了某⼀时刻JVM堆中对象使⽤情况,heapdump⽂件是指定时刻的Java堆栈的快照,是⼀种镜像⽂件。
2、产⽣heapdump(内存溢出)错误原因⼀般出于以下原因:1)JVM内存过⼩。
2)程序不严密。
3)产⽣过多的垃圾⽆法回收。
3、heapdump⽂件如何⽣成?使⽤ jmap 命令⽣成:jmap 命令是JDK提供的⽤于⽣成堆内存信息的⼯具,切换到JDK_HOME/bin⽬录下后,执⾏下⾯的命令⽣成Heaplinux环境:./jmap -dump:live,format=b,file=heap.hprof <pid>其中pid是JVM进程的id,heap.hprof是⽣成的heap dump⽂件,在执⾏命令的⽬录下⾯。
推荐此种⽅法。
如果我们只需要将dump中存活的对象导出,那么可以使⽤:live参数jmap -dump:live,format=b,file=heapLive.hprof 25764、常见heapdump⽂件分析⼯具:jhatjhat 是JDK⾃带的⽤于分析JVM Heap Dump⽂件的⼯具,使⽤下⾯的命令可以将堆⽂件的分析结果以HTML⽹页的形式进⾏展⽰:jhat <heap-dump-file>其中 heap-dump-file 是⽂件的路径和⽂件名,可以使⽤ -J-Xmx512m 参数设置命令的内存⼤⼩。
执⾏成功之后显⽰如下结果: 这个时候访问 http://localhost:7000/ 即可以看到结果了。
考虑到⽣产环境中⼏乎不可能在线对其进⾏分析,⼤都是采⽤离线分析,因此使⽤jmap+MAT⼯具最常见最科学的组合。
⼆:thread dump1、threaddump:记录CPU信息。
thread dump⽂件主要保存的是java应⽤中各线程在某⼀时刻的运⾏的位置,即执⾏到哪⼀个类的哪⼀个⽅法哪⼀个⾏上。
jvm dump参数
jvm dump参数在Java虚拟机(JVM)中,dump表示生成应用程序的内存快照。
这些快照可以用于分析应用程序的运行时状态,包括内存使用情况、线程状态等。
JVM提供了一些参数来控制生成dump文件的行为。
以下是常用的JVM dump参数:1. -XX:+HeapDumpOnOutOfMemoryError:在发生OutOfMemoryError错误时生成堆内存dump文件。
2. -XX:HeapDumpPath=<path>:设置生成堆内存dump文件的路径。
3. -XX:OnOutOfMemoryError=<command>:发生OutOfMemoryError错误时执行自定义命令。
4. -XX:+PrintGCApplicationStoppedTime:打印应用程序停止的时间。
5. -XX:+PrintGCDateStamps:打印GC发生的日期和时间。
6. -XX:+PrintGCDetails:打印GC的详细信息。
7. -XX:+PrintHeapAtGC:在每次GC之后打印堆内存的详细信息。
8. -XX:+PrintClassHistogram:打印当前运行时的类直方图。
9. -XX:+PrintVMOptions:打印JVM启动时的命令行选项。
10. -XX:+PrintCommandLineFlags:打印JVM启动时的命令行标记。
11. -XX:+CrashOnOutOfMemoryError:发生OutOfMemoryError错误时强制JVM终止。
这些是一些常用的JVM dump参数,可以根据需要进行配置。
在生成dump文件后,可以使用一些工具(如MAT、jmap等)对dump文件进行分析。
JavaDump分析
JavaDump分析JavaDump分析一、Java Dump概述Dump,即“转储”。
Java Dump可以保留Java虚拟机的瞬时快照。
相比于传统的控制台输出,提供了更多的信息用于分析运行系统状态及错误。
可弥补传统在Java平台上分析Bug手段的一些不足。
Java Dump分为两种:●线程Dump:纯文本格式。
包含所有线程的运行状态、调用栈、锁信息等。
●堆Dump:二进制格式,需要工具查看。
包含了线程Dump的所有信息,此外还包括系统信息、Java虚拟机参数以及堆对象的状态。
Java Dump的分析,特别适合于生产环境下,并且针对非功能性的问题,主要为:多线程并发、内存泄漏。
二、制作Dump1.Java虚拟机发行版不同Java虚拟机的Dump规范不完全相同,所以在制作Dump 时,需要注意虚拟机发行版。
●HotSpot VM:原Sun提供的官方Java虚拟机,支持Linux、Windows、Solaris平台。
●OpenJDK:Sun JDK的开源版本,1.6后跟HotSpot差别不太大了。
●JRockit:WebLogic使用的Java虚拟机,BEA开发。
●IBM J9 VM:IBM开发的Java虚拟机,AIX平台上的唯一实现。
2.原理3.注意事项1)Java虚拟机发行版使用相同的Java虚拟机发行版。
即意味着使用SunJDK的工具,连接SunJRE的应用系统来制作Dump。
2)版本要求●目标虚拟机必须为1.6或以及的jdk。
使用OOM参数制作堆Dump可使用1.5的jdk。
(各虚拟机差异较大)●制作工具需要使用相同发行版的jdk,并且建议1.6以上。
3)堆Dump格式相对纯文本的线程dump而言,堆Dump目前存在多种不同的格式。
●HPROF,Sun 的Java虚拟机的堆Dump格式。
●PHD,IBM Portable Heap Dump。
IBM J9 VM生成的Dump 格式。
4.使用虚拟机参数1)内存溢出时自动堆Dump为虚拟机增加启动参数:则当虚拟机发生OutOfMemoryError时,自动生成堆Dump。
怎样分析java线程堆栈日志
怎样分析java线程堆栈⽇志注: 该⽂章的原⽂是由 Tae Jin Gu 编写,原⽂地址为当有障碍,或者是⼀个基于 JAVA 的 WEB 应⽤运⾏的⽐预期慢的时候,我们需要使⽤thread dumps。
如果对于你来说,thread dumps是⾮常复杂的,这篇⽂章或许能对你有所帮助。
在这⾥我将解释在 JAVA 中什么是threads,他们的类型,怎么被创建的,怎样管理它们,你怎样从正在运⾏的应⽤中dump threads,最后你可以怎样分析它以及确定瓶颈或者是阻塞线程。
本⽂来⾃于 JAVA 应⽤程序长期调试经验的结果。
Java and Thread⼀个 web 服务器使⽤⼏⼗到⼏百个线程来处理⼤量并发⽤户,如果⼀个或多个线程使⽤相同的资源,线程之间的竞争就不可避免了,并且有时候可能会发⽣死锁。
Thread contention 是⼀个线程等待锁的⼀个状态,这个锁被另外⼀个线程持有,等待被释放,不同的线程频繁访问 WEB 应⽤的共享资源。
例如,记录⼀条⽇志,线程尝试记录⽇志之前必须先获取锁来访问共享资源。
死锁是线程竞争的⼀个特殊状态,⼀个或是多个线程在等待其他线程完成它们的任务为了完成它们⾃⼰的任务。
线程竞争会引起各种不同的问题,为了分析这些这些问题,你需要使⽤ dump threads,dump threads能给你提供每个线程的精确状态信息。
JAVA 线程的背景资料线程同步⼀个线程可以与其他线程在同⼀时间内被处理。
为了确保⼀致性,当多个线程试图使⽤共享资源的时候,通过使⽤hread synchronization在同⼀时间内,应该只有⼀个线程能访问共享资源JAVA 中的线程同步可以使⽤监视器,每个 JAVA 对象都有⼀个单独的监视器,这个监视器仅仅只能被⼀个线程拥有,对于拥有⼀个由不同的线程所拥有的监视器的线程,确实需要在队列中等待,以便其他线程释放它的监视器。
线程状态为了分析⼀个thread dump⽂件,你需要知道线程状态。
本地模拟内存溢出并分析Dump文件
本地模拟内存溢出并分析Dump⽂件java Dump⽂件分析前⾔dump⽂件是java虚拟机内存在某⼀时间点的快照⽂件,⼀般是.hprof⽂件,下⾯⾃⼰模拟⼀下本地内存溢出,⽣成dump⽂件,然后通过mat ⼯具分析的过程。
配置虚拟机参数要想本地模拟oom异常,那么建议将堆内存设置的⼩⼀点,那样容易触发-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${⽬录} -Xms20m -Xmx20m1. -XX:+HeapDumpOnOutOfMemoryError表⽰jvm发⽣oom异常时,⾃动⽣成dump⽂件,⽂件格式⼀般是:java_pid20804.hprof ,其中20804是java进程id2. -XX:HeapDumpPath=${⽬录},表⽰⽣成dump⽂件的⽬录,也可以指定⽂件名称,例如:-XX:HeapDumpPath=${⽬录}/java_heapdump.hprof,此步骤实验出了点问题,暂时跳过3. -Xms:表⽰给jvm分配的初始化堆内存4. -Xmx:表⽰最⼤堆内存模拟oom异常的程序public class Test1 {public static void main(String[] args) {List<Person> personList = new ArrayList<>();while (true){Person person = new Person();person.setDate(new Date());person.setAge(20);person.setName("test");personList.add(person);}}}很明显,⼀直创建Person对象,却⼜⽆法释放,很快就内存溢出了。
ng.OutOfMemoryError: GC overhead limit exceededDumping heap to java_pid21892.hprof ...Heap dump file created [33907612 bytes in 0.152 secs]Exception in thread "main" ng.OutOfMemoryError: GC overhead limit exceededat Test1.main(Test1.java:15)⽣成的⽂件名称是java_pid21892.hprof,在项⽬的根⽬录下⾯,⽂件⼤⼩33.9MMAT⼯具分析dump⽂件预览预览界⾯,能清楚的看到整个堆总内存18.7M,但是有18.3M的内存被⼀个类的对象占⽤了功能介绍1. Histogram柱状图:以class类的维度展⽰每个class类的实例存在的个数、占⽤的 [Shallow内存] 和 [Retained内存] ⼤⼩,可以分别排序显⽰,从图中看到,Person类的实例占⽤内存最⼤,⽽它就是没有回收引起内存溢出的对象2. Dominator Tree⽀配树:该视图以实例对象的维度展⽰当前堆内存中Retained Heap占⽤最⼤的对象,以及依赖这些对象存活的对象的树状结构展开会展⽰下⼀层⼦节点,可以这么理解:⽗节点引⽤了⼦节点,⼦节点没有被回收,所以⽗节点也没法被回收3. Thread Overview::可以看到线程栈/线程对象信息把线程进⾏⼀个排序,同样能看到引起内存溢出的是最上⾯线程⾥⾯的Person对象4. 可以选择展⽰什么样的报告信息,我们最开始打开dump⽂件时,会弹出⼀个窗⼝让我们选择,如果选错了这⾥可以重新选择5. 这⾥的功能⽐较强⼤,主要⽤来分析GC引⽤关系,每个对象到GCRoot的引⽤,可以在柱状图或者⽀配树界⾯⾥选择可疑对象进⾏分析,⽐较常⽤的两个是:Path to GC ROOTS和Merge Shortest Paths to GC Roots,当然选中对象双击,也能进⼊到这样的界⾯6. Group分组功能:在 Histogram视图和 Domiantor Tree视图时可操作,即以什么样的维度展⽰7. 将分析报告以什么样的格式导出,可选的有html、csv、txt。
java命令--jstack工具查看JVM堆栈信息
java命令--jstack⼯具查看JVM堆栈信息介绍jstack是java虚拟机⾃带的⼀种堆栈跟踪⼯具。
jstack⽤于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使⽤⽅式只⽀持以下的这种⽅式:jstack [-l] pid主要分为两个功能:a.针对活着的进程做本地的或远程的线程dump;b.针对core⽂件做线程dump。
jstack⽤于⽣成java虚拟机当前时刻的线程快照。
线程快照是当前java虚拟机内每⼀条线程正在执⾏的⽅法堆栈的集合,⽣成线程快照的主要⽬的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
线程出现停顿的时候通过jstack来查看各个线程的调⽤堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
如果java程序崩溃⽣成core⽂件,jstack⼯具可以⽤来获得core⽂件的java stack和native stack的信息,从⽽可以轻松地知道java程序是如何崩溃和在程序何处发⽣问题。
另外,jstack⼯具还可以附属到正在运⾏的java程序中,看到当时运⾏的java程序的java stack和native stack的信息, 如果现在运⾏的java程序呈现hung的状态,jstack是⾮常有⽤的。
So,jstack命令主要⽤来查看Java线程的调⽤堆栈的,可以⽤来分析线程问题(如死锁)。
# 线程状态想要通过jstack命令来分析线程的情况的话,⾸先要知道线程都有哪些状态,下⾯这些状态是我们使⽤jstack命令查看线程堆栈信息时可能会看到的线程的⼏种状态:NEW,未启动的。
不会出现在Dump中。
RUNNABLE,在虚拟机内执⾏的。
运⾏中状态,可能⾥⾯还能看到locked字样,表明它获得了某把锁。
java dump高级用法
Java dump通常指的是Java堆转储(Java Heap Dump),它是一个包含Java应用程序运行时堆内存信息的文件。
Java堆转储可以帮助开发者诊断和解决Java应用程序的性能问题、内存泄漏和其他相关的错误。
以下是一些Java堆转储的高级用法:
1.分析内存泄漏:内存泄漏是Java应用程序中常见的问题之一,它会导致应用程序的可用内存逐
渐减少,最终导致应用程序崩溃。
通过分析Java堆转储,可以确定哪些对象占用了大量的内存,哪些对象无法被垃圾回收器回收,从而找到内存泄漏的原因。
常用的工具包括Eclipse Memory Analyzer、VisualVM等。
2.诊断性能问题:性能问题通常表现为应用程序运行缓慢或响应时间过长。
通过分析Java堆转储,
可以找到导致性能问题的对象,例如大量的临时对象、大对象等。
这可以帮助开发者优化应用程序的内存使用和垃圾回收策略,从而提高应用程序的性能。
3.识别线程阻塞:线程阻塞是导致应用程序卡顿和死锁的原因之一。
通过分析Java堆转储,可以
找到导致线程阻塞的对象,例如锁、同步块等。
这可以帮助开发者优化线程的使用和管理,避免线程阻塞的发生。
4.识别内存溢出:内存溢出是Java应用程序中非常严重的问题,它会导致应用程序崩溃。
通过分
析Java堆转储,可以找到导致内存溢出的原因,例如大量的对象无法被垃圾回收器回收、内存泄漏等。
这可以帮助开发者及时发现和修复内存溢出问题。
Java Dump 的简单使用和MAT(Memory Analyzer Tool)分析工具使用
JAVA Dump 是当tomcat出现假死状态时,保留当前内存情况下记录二进制文件。
使用MAT工具进行分析内存泄漏问题。
第一步:需要在tomcat的catalina.sh中添加如下配置JAVA_OPTS="-Xms8192m -Xmx8192m -XX:PermSize=2048M -XX:MaxNewSize=2048m -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=你的文件路径只要tomcat出现内存泄漏(假死)状态就会保留下内存二进制文件。
(当然添加后要重启tomcat)第二步: 需要下载xxxx.hprof文件,这个可能会很大。
第三步:安装MAT下载https:///download/cdszdd8/10831451第四步:导如xxx.hprof文件这个过程比较漫长对了,在使用分析工具之前,一定要找一个比xxxx.hprof文件内存大机器进行分析(我这边分析了一个8G 的文件在16G内存的机器上运行分析的)第五步:导入点击工具file->Open Heap Dump 选择我们到处的.hprof文件(需要等....)等待完毕后如下图点击Leak Suspects这个是分析出的问题点击Details如下图工具定位到线程上点击线程查看线程情况找出是哪行代码出现的问题然后在返回上层点击查看数据返回情况最后定位到是一个SQL语句由于条件没有控制住导致查询数据800多万数据,都加载到内存占据内存3G多。
到此就可以找到问题了。
希望对大家有帮助。
写的不好大家多担待,谢谢观看。
jvm dump 参数
JVM Dump参数1. 什么是JVM DumpJava虚拟机(JVM)是Java程序的运行环境,它负责将Java字节码转换为机器码并执行程序。
JVM提供了许多工具和参数来监控和调试Java应用程序的运行状态。
其中一个重要的工具是JVM Dump,它可以帮助开发人员捕获应用程序在运行时的内存快照,以便分析和解决问题。
JVM Dump是一个线程转储工具,它会将Java应用程序的内存状态转储到一个文件中。
这个文件包含了JVM的堆栈信息、线程信息、对象信息等。
通过分析这些信息,开发人员可以了解应用程序在运行时的内存使用情况,找出内存泄漏、死锁等问题的根本原因。
2. JVM Dump的参数在使用JVM Dump工具时,可以通过一些参数来配置转储的行为。
下面是一些常用的JVM Dump参数:•-XX:+HeapDumpOnOutOfMemoryError:当发生OutOfMemoryError错误时,自动进行内存转储。
这对于识别内存泄漏问题非常有用。
•-XX:HeapDumpPath=:指定内存转储文件的保存路径。
默认情况下,转储文件会保存在当前工作目录下。
•-XX:OnOutOfMemoryError=:当发生OutOfMemoryError错误时,执行指定的命令。
可以用于自动化处理内存溢出问题。
•-XX:OnError=:当JVM发生致命错误时,执行指定的命令。
可以用于自动化处理意外终止的情况。
•-XX:OnCtrlBreak=:当接收到Ctrl-Break信号时,执行指定的命令。
可以用于手动触发内存转储。
•-XX:+PrintClassHistogram:打印Java堆中各个类的实例数量和占用内存大小的统计信息。
•-XX:+PrintHeapAtGC:在每次进行垃圾回收时,打印Java堆的详细信息。
•-XX:+PrintGCDetails:打印垃圾回收的详细信息,包括每次回收的时间、回收器类型、回收前后的堆内存使用情况等。
javadump文件怎么生成和分析-JMAP用法详解
javadump⽂件怎么⽣成和分析-JMAP⽤法详解jmap是java⾃带的⼯具
1. 查看整个JVM内存状态
jmap -heap [pid]
2. 查看JVM堆中对象详细占⽤情况
jmap -histo [pid]
3. 导出整个JVM 中内存信息,可以利⽤其它⼯具打开dump⽂件分析,例如jdk⾃带的visualvm⼯具
jmap -dump:file=⽂件名.dump [pid]
补充知识:Jmap导出java运⾏中的堆内存dump及Jprofiler分析⽅法
1.jmap导出dump
1.1运⾏程序的java\bin⽬录,执⾏jmap -dump:format=b,file=⽂件名 [pid]
1.2⽣成dump⽂件
2.Jprofiler分析⽅法
2.1 将jmap导出的⽂件web.dump⽂件更改后缀为web.jsp,*.jps为Jprofiler可识别后缀。
使⽤jprofiler打开web.jps⽂件
这⾥可以看到内存使⽤情况,查看具体占⽤内存的是什么,然后选中该项右键
然后选择references,在⾥⾯选择cumulated incoming references查看具体
可以看到具体内存占⽤的什么
以上这篇java dump⽂件怎么⽣成和分析-JMAP⽤法详解就是⼩编分享给⼤家的全部内容了,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
Java线程Dump分析工具jstack解析及使用场景
Java线程Dump分析⼯具jstack解析及使⽤场景jstack⽤于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使⽤⽅式只⽀持以下的这种⽅式:jstack [-l][F] pid如果java程序崩溃⽣成core⽂件,jstack⼯具可以⽤来获得core⽂件的java stack和native stack的信息,从⽽可以轻松地知道java程序是如何崩溃和在程序何处发⽣问题。
另外,jstack⼯具还可以附属到正在运⾏的java程序中,看到当时运⾏的java程序的java stack和native stack的信息, 如果现在运⾏的java程序呈现hung的状态,jstack是⾮常有⽤的。
进程处于hung死状态可以⽤-F强制打出stack。
dump ⽂件⾥,值得关注的线程状态有:死锁,Deadlock(重点关注)执⾏中,Runnable等待资源,Waiting on condition(重点关注)等待获取监视器,Waiting on monitor entry(重点关注)暂停,Suspended对象等待中,Object.wait() 或 TIMED_WAITING阻塞,Blocked(重点关注)停⽌,Parked在摘了另⼀篇博客的三种场景:实例⼀:Waiting to lock 和 Blocked"RMI TCP Connection(267865)-172.16.5.25" daemon prio=10 tid=0x00007fd508371000 nid=0x55ae waiting for monitor entry [0x00007fd4f8684000]ng.Thread.State: BLOCKED (on object monitor)at org.apache.log4j.Category.callAppenders(Category.java:201)- waiting to lock <0x00000000acf4d0c0> (a org.apache.log4j.Logger)at org.apache.log4j.Category.forcedLog(Category.java:388)at org.apache.log4j.Category.log(Category.java:853)at mons.logging.impl.Log4JLogger.warn(Log4JLogger.java:234)at ng.cache.remote.SpyMemcachedClient.get(SpyMemcachedClient.java:110)说明:1)线程状态是 Blocked,阻塞状态。
thread dump分析
1.1Thread dump定位瓶颈1.1.1Thread dump概述JAVA 的线程 DUMP,就象当前 JAVA进程的一个快照,打印出所有线程的状态和调用堆栈,以及Monitor的状态。
在实际运行中,往往一次 dump的信息,还不足以确认问题。
建议产生三次dump信息,如果每次 dump都指向同一个问题,我们才确定问题的典型性。
1.1.2分析过程举例以实际环境举例1.1.2.1产生dump日志步骤如下1.对主机的中心进行加压, 使中心每秒钟处理约60笔交易.2.对中心执行thread dump (kill -3 PID)3.取出thread dump日志进行分析4.如下是截取的其中一个thread 的信息,标黄部分是需要关注的部分."IS " prio=7 tid=01b8fde8 nid=288 lwp_id=5016325 waiting for monitor entry [32082000..32080738]at app.b2b.server.jdbc.JDBCConnectionPool.getConnection(JDBCConnectionPool.java:330) - waiting to lock <47c9e5d0> (a app.b2b.server.jdbc.JDBCConnectionPool)-------------------------------------中间略取一部分-----------------at com.wm.app.b2b.server.ServiceThread.run(ServiceThread.java:80)- locked <53c2af70> (a app.b2b.server.ServiceThread)at com.wm.util.pool.PooledThread.run(PooledThread.java:118)- locked <43de02c8> (a app.b2b.server.TMPooledThread)at ng.Thread.run(Thread.java:595)1.1.2.2线程状态分析在多线程的 JAVA程序中,实现线程之间的同步,就要说说 Monitor。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Java线程dump分析金蝶中间件有限公司2013年3月14日版本历史 (2)目录 (3)第1章JAVA线程DUMP (4)1.1什么是J AVA线程D UMP (4)1.2如何生成 (4)第2章线程DUMP分析 (5)2.1JVM线程 (5)2.2线程状态分析 (5)2.2.1Runnable (5)2.2.2Waiting on condition (5)2.2.3Waiting for monitor entry 和in Object.wait() (6)2.3JDK5.0的LOCK (8)第3章案例分析 (9)3.1死锁 (9)3.2热锁 (9)1.1 什么是Java线程Dump线程Dump是非常有用的诊断Java应用问题的工具,每一个Java虚拟机都有及时生成显示所有线程在某一点状态的线程Dump的能力。
虽然各个Java虚拟机线程dump打印输出格式上略微有一些不同,但是线程dump出来的信息包含线程基本信息;线程的运行状态、标识和调用的堆栈;调用的堆栈包含完整的类名,所执行的方法,如果可能的话还有源代码的行数。
JVM(java虚拟机)中的许多问题都可以使用线程Dump文件来进行诊断,其中比较典型的包括线程阻塞,CPU 使用率过高,JVM Crash,堆内存不足,和类装载等问题。
1.2 如何生成在不同的操作系统下,产生线程DUMP的方式是不同的:1)在windows环境中在启动程序的控制台里敲:Ctrl - Break,线程的dump会产生在标准输出中(缺省标准输出就是控制台,如果对输出进行了重定向,则要查看输出文件)。
2)在unix,linux和MacOS 环境中在控制台中敲:Ctrl-\,或者,用“kill -3 <pid>”,或者“kill –QUIT <pid>”。
Pid是用所关注的JA V A进程号,您可以用“ps -ef | grep java”找到,或者使用JDK 5.0中的“jps -v”命令获得。
3)在各个操作系统平台,都可以用JDK 5.0工具包中的jstack <pid>这里要注意的是:1.不同的JAVA虚机的线程DUMP的创建方法和文件格式是不一样的,不同的JVM版本,dump信息也有差别。
本文中,只以SUN的hotspot JVM 5.0_06 为例。
在实际运行中,往往一次dump的信息,还不足以确认问题。
建议产生三次dump信息,如果每次dump都指向同一个问题,我们才确定问题的典型性。
2.1 JVM线程在线程中,有一些JVM内部的后台线程,来执行譬如垃圾回收,或者低内存的检测等任务,这些线程往往在JVM初始化的时候就存在,如下所示:"Low Memory Detector" daemon prio=10 tid=0x081465f8 nid=0x7 runnable [0x00000000..0x00000000]如有红色标注的daemon字样,表明是后台线程。
实际分析中观察的更多的是用户线程,如下所示:其中包括:1.线程的一些基本信息:名称、优先级及id2.线程状态:waiting on condition3.线程的调用栈4.线程锁住的资源:locked <0x3f63d600>2.2 线程状态分析正如我们刚看到的那样,线程的状态是一个重要的指标,它会显示在线程Stacktrace的头一行结尾的地方。
2.2.1 R unnable该状态表示线程具备所有运行条件,在运行队列中准备操作系统的调度,或者正在运行。
2.2.2 W aiting on condition该状态出现在线程等待某个条件的发生。
具体是什么原因,可以结合stacktrace来分析。
最常见的情况是线程在等待网络的读写,比如当网络数据没有准备好读时,线程处于这种等待状态,而一旦有数据准备好读之后,线程会重新激活,读取并处理数据。
在Java引入NewIO之前,对于每个网络连接,都有一个对应的线程来处理网络的读写操作,即使没有可读写的数据,线程仍然阻塞在读写操作上,这样有可能造成资源浪费,而且给操作系统的线程调度也带来压力。
在NewIO里采用了新的机制,编写的服务器程序的性能和可扩展性都得到提高。
如果发现有大量的线程都在处在Wait on condition,从线程stack看,正等待网络读写,这可能是一个网络瓶颈的征兆。
因为网络阻塞导致线程无法执行。
一种情况是网络非常忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。
所以要结合系统的一些性能观察工具来综合分析,比如netstat统计单位时间的发送包的数目,如果很明显超过了所在网络带宽的限制; 观察cpu的利用率,如果系统态的CPU时间,相对于用户态的CPU时间比例较高,这些都指向由于网络带宽所限导致的网络瓶颈。
另外一种出现Wait on condition的常见情况是该线程在sleep,等待sleep的时间到了时候,将被唤醒。
2.2.3 W aiting for monitor entry 和in Object.wait()在多线程的JA V A程序中,实现线程之间的同步,就要说说Monitor。
Monitor是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者Class的锁。
每一个对象都有,也仅有一个monitor。
下面这个图,描述了线程和Monitor之间关系,以及线程的状态转换图:从图中可以看出,每个Monitor在某个时刻,只能被一个线程拥有,该线程就是“Active Thread”,而其它线程都是“Waiting Thread”,分别在两个队列“Entry Set”和“Wait Set”里面等候。
在“Entry Set”中等待的线程状态是“Waiting for monitor entry”,而在“Wait Set”中等待的线程状态是“in Object.wait()”。
先看“Entry Set”里面的线程。
我们称被synchronized保护起来的代码段为临界区。
当一个线程申请进入临界区时,它就进入了“Entry Set”队列。
对应的代码就像:这时有两种可能性:●该monitor不被其它线程拥有,Entry Set里面也没有其它等待线程。
本线程即成为相应类或者对象的Monitor的Owner,执行临界区的代码(也就是请求的资源没有被锁住)●该monitor被其它线程拥有,本线程在Entry Set队列中等待。
(也就是请求的资源正在被其它线程处理,也就是锁住了,要等待锁的解除)在第一种情况下,线程将处于“Runnable”的状态,而第二种情况下,线程DUMP会显示处于“waiting for monitor entry”。
如下所示:临界区的设置,是为了保证其内部的代码执行的原子性和完整性。
但是因为临界区在任何时间只允许线程串行通过,这和我们多线程的程序的初衷是相反的。
如果在多线程的程序中,大量使用synchronized,或者不适当的使用了它,会造成大量线程在临界区的入口等待,造成系统的性能大幅下降。
如果在线程DUMP中发现了这个情况,应该审查源码,改进程序。
现在再来看现在线程为什么会进入“Wait Set”。
当线程获得了Monitor,进入了临界区之后,如果发现线程继续运行的条件没有满足,它则调用对象(一般就是被synchronized 的对象)的wait() 方法,放弃了Monitor,进入“Wait Set”队列。
只有当别的线程在该对象上调用了notify() 或者notifyAll() ,“Wait Set”队列中线程才得到机会去竞争,但是只有一个线程获得对象的Monitor,恢复到运行态。
在“Wait Set”中的线程,DUMP中表现为:in Object.wait(),类似于:仔细观察上面的DUMP信息,你会发现它有以下两行:这里需要解释一下,为什么先lock了这个对象,然后又waiting on同一个对象呢?让我们看看这个线程对应的代码:线程的执行中,先用synchronized 获得了这个对象的Monitor(对应于locked <0xef63beb8> )。
当执行到obj.wait(), 线程即放弃了Monitor的所有权,进入“wait set”队列(对应于waiting on <0xef63beb8> )。
往往在程序中,会出现多个类似的线程,他们都有相似的DUMP信息。
这也可能是正常的。
比如,在程序中,有多个服务线程,设计成从一个队列里面读取请求数据。
这个队列就是lock以及waiting on 的对象。
当队列为空的时候,这些线程都会在这个队列上等待,直到队列有了数据,这些线程被Notify,当然只有一个线程获得了lock,继续执行,而其它线程继续等待。
2.3 JDK5.0的lock上面提到如果synchronized和monitor机制运用不当,可能会造成多线程程序的性能问题。
在JDK 5.0中,引入了Lock机制,从而使开发者能更灵活的开发高性能的并发多线程程序,可以替代以往JDK中的synchronized和Monitor的机制。
但是,要注意的是,因为Lock类只是一个普通类,JVM无从得知Lock对象的占用情况,所以在线程DUMP中,也不会包含关于Lock的信息,关于死锁等问题,就不如用synchronized的编程方式容易识别。
3.1 死锁在多线程程序的编写中,如果不适当的运用同步机制,则有可能造成程序的死锁,经常表现为程序的停顿,或者不再响应用户的请求。
比如在下面这个示例中,是个较为典型的死锁情况:可以注意到线程1在等待锁<0x22c19f18>,自己锁住了<0x22c19f20>,而线程0正好在等待<0x22c19f20>,而把<0x22c19f18>锁住,从而形成了循环等待,造成死锁。
在JAVA 5中加强了对死锁的检测。
线程Dump中可以直接报告出Java级别的死锁,如下所示:3.2 热锁热锁,也往往是导致系统性能瓶颈的主要因素。
其表现特征为,由于多个线程对临界区,或者锁的竞争,可能出现:●频繁的线程的上下文切换:从操作系统对线程的调度来看,当线程在等待资源而阻塞的时候,操作系统会将之切换出来,放到等待的队列,当线程获得资源之后,调度算法会将这个线程切换进去,放到执行队列中。
●大量的系统调用:因为线程的上下文切换,以及热锁的竞争,或者临界区的频繁的进出,都可能导致大量的系统调用。
●大部分CPU开销用在“系统态”:线程上下文切换,和系统调用,都会导致CPU在“系统态”运行,换而言之,虽然系统很忙碌,但是CPU用在“用户态”的比例较小,应用程序得不到充分的CPU资源。