`

如何分析Java虚拟机死锁

阅读更多

英文资料:

Thread Dump and Concurrency Locks

 

Thread dumps are very useful for diagnosing synchronization related problems such as deadlocks on object monitors. Ctrl-\ on Solaris/Linux or Ctrl-Break on Windows has been a common way to get a thread dump of a running application. O n Solaris or Linux, you can send a QUIT signal to the target application. The target application in both cases prints a thread dump to the standard output and also detects if there is any deadlock involving object monitors.

jstack , a new troubleshooting utility introduced in Tiger (J2SE 5.0), provides another way to obtain a thread dump of an application. Alan Bateman has a nice blog about jstack and its several improvements in Mustang (Java SE 6). Mustang jstack works like a remote Ctrl-\ or Ctrl-Break if you are on Windows.

jconsole is JMX-complaint GUI tool which allows you to get a thread dump on the fly. The "Using JConsole to Monitor Applications " article gives you an overview of the Tiger monitoring and management functionality.

Mustang extends the thread dump, jstack, and jconsole to support java.util.concurrent.locks to improve its diagnosability. For example, the Threads tab in the Mustang jconsole now shows which synchronizer a thread is waiting to acquire when the thread is blocked to lock a ReentrantLock and also which thread is owning that lock.

 

In addition, it has a new "detect deadlock" button (in the bottom). When you click on the "detect deadlock" button, it will send a request to the target application to perform the deadlock detection operation. If the target application is running on Mustang, it finds deadlocks involving both object monitors as well as the java.util.concurrent.locks. If the target application is running on Tiger, it finds deadlocks involving object monitors only. Each deadlock cycle will be displayed in a separate Deadlock tab.

 

Click here to see a wider form of this screenshot.

JDK 6 has a nice demo FullThreadDump under $JDK_HOME/demo/management/FullThreadDump where JDK_HOME is the location of your JDK 6. This demo has been included in JDK 5.0 and is updated to use the new Mustang API. It demonstrates the use of the java.lang.management API to get the thread dump and detect deadlock programmatically.

 

中文资料:

我发现现在网上没有好好讲这个的,少数的几篇文章都是大谈自己的工具,却没把方法讲清楚。我决定以我以前碰到的case为例写一篇来分享。到目前为止,我认为分析Java代码问题的最有效的工具仍然是java thread dump。

 

原因:

- 任何操作系统平台下都可以使用。

- 在多数情况下,可以在生产环境中使用。

- 和操作系统提供的工具相比,java thread dump给出的信息是直白的,直接对应到应用代码。

- 它对被分析的系统干扰很小,因此能反应真实的问题。而其它很多profiling或Instrument工具本身对JVM运行有很大的干扰,经常不能暴露出真正的问题,而且这种工具不能用于生产系统。

我觉得在通常情况下分析Java虚拟机死锁比分析内存泄漏要容易的多。因为死锁发生时,JVM通常处于挂起状态(hang住了),thread dump可以给出静态稳定的信息,查找死锁只需要查找有问题的线程。而内存泄漏的问题却很难界定,一个运行的JVM里有无数对象存在,只有写程序的人才知道哪些对象是垃圾,而哪些不是,而且对象的引用关系非常复杂,很难得到一份清晰的对象引用图。

Java虚拟机死锁发生时,从操作系统上观察,虚拟机的CPU占用率为零,很快会从top或prstat的输出中消失。这时你就可以收集thread dump了,Unix/Linux 下是kill -3 <JVM pid> ,在Windows下可以在JVM的console窗口上敲Ctrl-Break。根据不同的设置,thread dump会输出到当前控制台上或应用服务器的日志里。

拿到java thread dump后,你要做的就是查找"waiting for monitor entry"的thread,如果大量thread都在等待给同一个地址上锁(因为对于Java,一个对象只有一把锁),这说明很可能死锁发生了。比如:

"service-j2ee" prio=5 tid=0x024f1c28 nid=0x125 waiting for monitor entry

[62a3e000..62a3f690]

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

com.sun.enterprise.resource.IASNonSharedResourcePool.internalGetResource(IASNonS

haredResourcePool.java:625)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: - waiting to

lock <0x965d8110> (a com.sun.enterprise.resource.IASNonSharedResourcePool)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

com.sun.enterprise.resource.IASNonSharedResourcePool.getResource(IASNonSharedRes

ourcePool.java:520)

................

 

为了确定问题,常常需要在隔两分钟后再次收集一次thread dump,如果得到的输出相同,仍然是大量thread都在等待给同一个地址上锁,那么肯定是死锁了。

如何找到当前持有锁的线程是解决问题的关键。方法是搜索thread dump,查找"locked <0x965d8110>", 找到持有锁的线程。

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: "Thread-20" daemon prio=5 tid=0x01394f18

nid=0x109 runnable [6716f000..6716fc28]

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

java.net.SocketInputStream.socketRead0(Native Method)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

java.net.SocketInputStream.read(SocketInputStream.java:129)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at oracle.net.ns.Packet.receive(Unknown

Source)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

oracle.net.ns.DataPacket.receive(Unknown Source)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

oracle.net.ns.NetInputStream.getNextPacket(Unknown Source)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

oracle.net.ns.NetInputStream.read(Unknown Source)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

oracle.net.ns.NetInputStream.read(Unknown Source)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

oracle.net.ns.NetInputStream.read(Unknown Source)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

oracle.jdbc.ttc7.MAREngine.unmarshalUB1(MAREngine.java:929)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

oracle.jdbc.ttc7.MAREngine.unmarshalSB1(MAREngine.java:893)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

oracle.jdbc.ttc7.Ocommoncall.receive(Ocommoncall.java:106)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

oracle.jdbc.ttc7.TTC7Protocol.logoff(TTC7Protocol.java:396)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: - locked <0x954f47a0> (a

oracle.jdbc.ttc7.TTC7Protocol)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

oracle.jdbc.driver.OracleConnection.close(OracleConnection.java:1518)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: - locked <0x954f4520> (a

oracle.jdbc.driver.OracleConnection)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

com.sun.enterprise.resource.JdbcUrlAllocator.destroyResource(JdbcUrlAllocator.java:122)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

com.sun.enterprise.resource.IASNonSharedResourcePool.destroyResource(IASNonSharedResourcePool.java:8

72)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

com.sun.enterprise.resource.IASNonSharedResourcePool.resizePool(IASNonSharedResourcePool.java:1086)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: - locked <0x965d8110> (a

com.sun.enterprise.resource.IASNonSharedResourcePool)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

com.sun.enterprise.resource.IASNonSharedResourcePool$Resizer.run(IASNonSharedResourcePool.java:1178)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

java.util.TimerThread.mainLoop(Timer.java:432)

[27/Jun/2006:10:03:08] WARNING (26140): CORE3283: stderr: at

java.util.TimerThread.run(Timer.java:382)

 

在这个例子里,持有锁的线程在等待Oracle返回结果,却始终等不到响应,因此发生了死锁。

如果持有锁的线程还在等待给另一个对象上锁,那么还是按上面的办法顺藤摸瓜,直到找到死锁的根源为止。

另外,在thread dump里还会经常看到这样的线程,它们是等待一个条件而主动放弃锁的线程。例如:

"Thread-1" daemon prio=5 tid=0x014e97a8 nid=0x80 in Object.wait() [68c6f000..68c6fc28]

at java.lang.Object.wait(Native Method)

- waiting on <0x95b07178> (a java.util.LinkedList)

at com.iplanet.ias.util.collection.BlockingQueue.remove(BlockingQueue.java:258)

- locked <0x95b07178> (a java.util.LinkedList)

at com.iplanet.ias.util.threadpool.FastThreadPool$ThreadPoolThread.run(FastThreadPool.java:241)

at java.lang.Thread.run(Thread.java:534)

有时也会需要分析这类线程,尤其是线程等待的条件。

其实,Java thread dump并不只用于分析死锁,其它Java应用运行时古怪的行为都可以用thread dump来分析。

最后,在Java SE 5里,增加了jstack的工具,也可以获取thread dump。在Java SE 6里, 通过jconsole的图形化工具也可以方便地查找涉及object monitors 和java.util.concurrent.locks死锁。

 

分享到:
评论

相关推荐

    后端JAVA虚拟机JVM调优必备工具

    找到需要分析的jvm进程 3.使用jstack [pid] &gt; /tmp/sdapjvmlog.txt导出进程的详细日志 4.使用程序打开导出的进程日志 二、此工具线程的几种状态 1.死锁,Deadlock(重点关注)  2.执行中,Runnable(重点关注) ...

    深入理解Java虚拟机视频教程(jvm性能调优+内存模型+虚拟机原理)视频教程

    第20节Java虚拟机-高性能Java虚拟机00:02:58分钟 | 第21节Java虚拟机-TaobaoVM00:03:06分钟 | 第22节Java内存区域-简介00:07:56分钟 | 第23节Java内存区域-Java虚拟机栈00:12:04分钟 | 第24节Java内存区域-程序...

    Java Pathfinder(JPF)完全安装配置过程(2013年6月)

    它的内核是一个Java虚拟机(JVM),可用于系统地探测程序所有可能的执行路径,以避免死锁或无法处理的异常之类的情况发生。与传统的调试程序不同,Java PathFinder报告导致缺陷的整个执行路径。Java PathFinder特别...

    java开源包8

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java高级特性,涵盖了多种java常用的一些例子

    Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 Java 注解用于为 Java 反射机制 在运行状态中,对于任意一个类能够获取类中的所有属性和方法,对于任意一个对象能够调用对象中的属性和方法,这种动态...

    深入理解JVM内存结构及运行原理全套视频加资料.txt

     第20讲 Java虚拟机-高性能Java虚拟机 00:02:58  第21讲 Java虚拟机-TaobaoVM 00:03:06  第22讲 Java内存区域-简介 00:07:56  第23讲 Java内存区域-Java虚拟机栈 00:12:04  第24讲 Java内存区域-程序...

    JAVA上百实例源码以及开源项目

     Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...

    java开源包4

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    JAVA上百实例源码以及开源项目源代码

    Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来...

    java开源包101

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包11

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包6

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包9

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包10

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包5

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java初学者必看

    1.7.2 Java虚拟机的生命周期 1.7.3 Java虚拟机的体系结构 1.8 垃圾收集器 1.9 本章习题 第2章 Java开发环境 2.1 J2SE的下载和安装 2.1.1 J2SE的下载 2.1.2 J2SE的安装 2.2 环境变量的配置与测试 2.2.1 设置...

    java开源包1

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包3

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java jdk实列宝典 光盘源代码

    一个死锁的例子; 定时器Timer:包括在指定时间执行任务,在指定时间之后执行任务以及在某个时间之后每隔时间段重复执行的任务; 9 Java GUI 日历:使用swing和awt实现一个图形化的日历可以查询星期、日期和年份信息...

    java 类加载调试

    Java™ 虚拟机的基础。虽然开収人员一般对类装入的基础有良好的掌握,但是当问题収生时,在诊断问题和确定解决方案方面可能迓要有一定的困难。在返仹由四部分组成的系列中,Lakshmi Shankar 和 Simon Burns 讨论了在...

Global site tag (gtag.js) - Google Analytics