怎样使用jstack诊断Java应用程序故障(转)

 

        最近一段时间,我们的生产系统升级频繁出现故障,具体故障现象是启动后10来分钟就出现交易缓慢,处理线程耗尽等现象,并且故障发生的频率蛮高的。经过详细的诊断和排查,终于发现了问题,是groovy在osgi中运行会出现classloader死锁,最后我们也解决了这个问题。 
        如果单靠通过查看代码是很难去发现这个问题,在这一次故障排查中,我也学到了怎样更好的使用jvm监控工具来进行诊断,主要用到了jstack和jmap命令,jmap上次已经讲过就不再讲了,下面就一个例子来讲怎么使用jstack来对的Java程序进行诊断。 
        首先让我们来了解一下jstack这个命令的作用,jstack 是一个可以返回在应用程序上运行的各种各样线程的一个完整转储的实用程序,您可以使用它查明问题。jstack [-l] <pid>,jpid可以通过使用jps命令来查看当前Java程序的jpid值,-l是可选参数,它可以显示线程阻塞/死锁情况。 

/**
 * 死锁例子
 */
public class DeadLock {

    public static void main(String[] args) {
        final Object obj_1 = new Object(), obj_2 = new Object();

        Thread t1 = new Thread("t1"){
            @Override
            public void run() {
                synchronized (obj_1) {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {}

                    synchronized (obj_2) {
                        System.out.println("thread t1 done.");
                    }
                }
            }
        };

        Thread t2 = new Thread("t2"){
            @Override
            public void run() {
                synchronized (obj_2) {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {}

                    synchronized (obj_1) {
                        System.out.println("thread t2 done.");
                    }
                }
            }
        };

        t1.start();
        t2.start();
    }

}

以上DeadLock类是一个死锁的例子,假使在我们不知情的情况下,运行DeadLock后,发现等了N久都没有在屏幕打印线程完成信息。这个时候我们就可以使用jps查看该程序的jpid值和使用jstack来生产堆栈结果问题。

$ java -cp deadlock.jar DeadLock &
$ 

 

$ jps
  3076 Jps
  448 DeadLock
$ jstack -l 448 > deadlock.jstack

 

结果文件deadlock.jstack内容如下: 

2011-03-20 23:05:20
Full thread dump Java HotSpot(TM) Client VM (19.1-b02 mixed mode, sharing):

"DestroyJavaVM" prio=6 tid=0x00316800 nid=0x9fc waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"t2" prio=6 tid=0x02bcf000 nid=0xc70 waiting for monitor entry [0x02f6f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.demo.DeadLock$2.run(DeadLock.java:40)
    - waiting to lock <0x22a297a8> (a java.lang.Object)
    - locked <0x22a297b0> (a java.lang.Object)

   Locked ownable synchronizers:
    - None

"t1" prio=6 tid=0x02bce400 nid=0xba0 waiting for monitor entry [0x02f1f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.demo.DeadLock$1.run(DeadLock.java:25)
    - waiting to lock <0x22a297b0> (a java.lang.Object)
    - locked <0x22a297a8> (a java.lang.Object)

   Locked ownable synchronizers:
    - None

"Low Memory Detector" daemon prio=6 tid=0x02bb9400 nid=0xa6c runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"CompilerThread0" daemon prio=10 tid=0x02bb2800 nid=0xcb8 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Attach Listener" daemon prio=10 tid=0x02bb1000 nid=0x7f4 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Signal Dispatcher" daemon prio=10 tid=0x02bd2800 nid=0xd80 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Finalizer" daemon prio=8 tid=0x02bab000 nid=0xe1c in Object.wait() [0x02d3f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x229e1148> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <0x229e1148> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

   Locked ownable synchronizers:
    - None

"Reference Handler" daemon prio=10 tid=0x02ba6800 nid=0xbe0 in Object.wait() [0x02cef000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x229e1048> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <0x229e1048> (a java.lang.ref.Reference$Lock)

   Locked ownable synchronizers:
    - None

"VM Thread" prio=10 tid=0x02b6a400 nid=0x568 runnable 

"VM Periodic Task Thread" prio=10 tid=0x02bc8400 nid=0x75c waiting on condition 

JNI global references: 878

Found one Java-level deadlock:
=============================
"t2":
  waiting to lock monitor 0x02baaeec (object 0x22a297a8, a java.lang.Object),
  which is held by "t1"
"t1":
  waiting to lock monitor 0x02baa2bc (object 0x22a297b0, a java.lang.Object),
  which is held by "t2"

Java stack information for the threads listed above:
===================================================
"t2":
    at com.demo.DeadLock$2.run(DeadLock.java:40)
    - waiting to lock <0x22a297a8> (a java.lang.Object)
    - locked <0x22a297b0> (a java.lang.Object)
"t1":
    at com.demo.DeadLock$1.run(DeadLock.java:25)
    - waiting to lock <0x22a297b0> (a java.lang.Object)
    - locked <0x22a297a8> (a java.lang.Object)

Found 1 deadlock.

从这个结果文件我们一看到发现了一个死锁,具体是线程t2在等待线程t1,而线程t1在等待线程t2造成的,同时也记录了线程的堆栈和代码行数,通过这个堆栈和行数我们就可以去检查对应的代码块,从而发现问题和解决问题。

http://crane-ding.iteye.com/blog/968862

 

时间: 2024-10-01 14:08:52

怎样使用jstack诊断Java应用程序故障(转)的相关文章

诊断Java代码: 设计可扩展应用程序,第3部分

对应于我们上一篇" 诊断 Java 代码"中所讨论的透明盒可扩展性,黑盒可扩展性是指,在源代码既不能查看也不能修改时,可以扩展软件系统的方法.通常通过系统配置或使用特定于应用程序的脚本语言来进行这样的扩展.在本专题中,Eric Allen 讨论了何时设计黑盒可 扩展性的系统是有意义的,并提供了如何有效地实现这一设计的一些想法.阅读了本文后,您将知道何时使用黑盒并掌握如何实现它的一些技巧. 我已在以前的文章中谈到了代码重用设计策略的重要性(主要是因为各种信息处理任务的差异和相应费用的增加

诊断Java代码: 设计可扩展的应用程序,第2部分

玻璃箱可扩展性是指这样一种方式:软件系统可在源代码可以查看而不可以修改时被扩展 ― 它是黑箱设计(在这里构建扩展时,不查看原始代码)和开放箱设计(扩展代码直接写入到基础代码)的折衷.因为新的扩展直接建立在原始代码基础上,但不改动原始代码,所以,玻璃箱设计或许是扩展一个软件系统最有效.最安全的方法.在 诊断 Java 代码的这一部分中,Eric Allen 详述了上个月谈及的玻璃箱可扩展性主题.读完本文后,您将知道什么时候使用玻璃箱,并将获得一些如何实现它的提示. 随着信息处理任务(和与之相关的成

LINUX类主机JAVA应用程序占用CPU、内存过高分析手段

转载声明:本文为DBA+社群原创文章,转载必须连同本订阅号二维码全文转载,并注明作者名字及来源:DBA+社群(dbaplus).   做为一个IT运维人员,通常在运维过程中会遇到各种各样的问题,系统问题.应用问题.程序问题,而在这当中必然会涉及到性能问题,当用户量过大,或者服务器性能不足以支持大用户量,但同时又得不到扩容的情况下,进行性能分析,并对系统.应用.程序进行优化则显得尤为重要,同时也是节省资源的一种必不可少的手段,目前大多数的运维产品都是基于JAVA语言开发的,下面我给大家介绍一下在l

诊断Java代码

诊断Java代码: Broken Dispatch错误模式 诊断Java代码: Double Descent错误模式 诊断Java代码: Impostor Type错误模式 诊断Java代码: Java编程中的断言和时态逻辑 诊断Java代码: Liar View错误模式 诊断Java代码: Repl提供交互式评价 诊断Java代码: 单元测试与自动化代码分析协同工作 诊断Java代码: 将时态逻辑用于错误模式 诊断Java代码: 进行记录器测试以正确调用方法 诊断Java代码: 空标志错误模式

诊断Java代码: Impostor Type错误模式

当使用字段中特殊的标记来区别对象类型时,可能会产生标记对相关数据误贴标签的错误 ― 通称为 Impostor Type 错误模式.在诊断 Java 代码的这一部分中,Eric Allen 对这个错误的症状和起因进行了分析,详细说明了预防错误发生的方法,并讨论了一种吸引人的混合实现方法,这种方法不使用 impostor type,但最后,还是有很多相同的缺点产生.请在 讨论论坛与作者及其他读者分享您对本文的看法. 程序中除了最无关紧要的部分外都要对某些数据类型进行操作.静态类型系统提供了一种方法,

诊断Java代码:孤线程(Orphaned Thread)错误模式

在多线程代码中,使用驱动其它线程所负责的动作的单个主线程是常见的.这个主线程发送消息,通常是通过把它们放到一个队列中,然后其它线程处理这些消息.但是如果主线程抛出一个异常,那么剩余的线程会继续运行,等待更多输入到该队列,导致程序冻结.在诊断 Java 代码的这一部分中,专职 Java 开发者兼兼职捉虫者 Eric Allen 讨论检测.修复和避免这一错误模式. 用多线程编写代码对程序员大有好处.多线程能使编程(和程序)进行得快得多,而且代码能有效得多地使用资源.然而,跟生活中的很多事情一样,多线

如何诊断和排除电脑故障十种方法

诊断和排除电脑故障,这是运行电脑应当具备的技能.现提供以下十种方法--注册表恢复法.精简启动法 .logged跟踪法 .程序升级法,等等... 环境检查法 对于一些突如其来的硬件故障,如开机无显示等.我们先不要进行深入的考虑,因为往往我们会忽略一些细节问题.首先我们应该看看那些显而易见的东西:如有没有接通电源?开关是否已打开?电源插座有没有通电?是不是所有的接线都连接上了?或许问题的根源就在其中. CMOS还原法 有些用户往往会因为好奇而改动主板CMOS里的一些设置,而这恰恰是导致故障发生的一个

如何通过禁用Java小程序脚本解决网页内容复制不了等问题

  平常我们会在浏览器中浏览某些网站网页内容,当我们看到精彩文章信息时也会通过复制粘贴的形式来保存,但有用户在复制网页内容时提示"无法复制"的问题,这给我们收集网页内容带来麻烦,其实我们可以通过win7 64位浏览器Internet区域禁用Java小程序脚本来解决网页内容无法复制的问题,下面来看看具体设置教程吧. 设置步骤如下所示: 1.先打开浏览器,点击浏览器上面的"工具--Internet选项"选项; 2.这时候会弹出的一个对话框,直接将其切换到"安全

Java开发者的福音:使用 Visual Studio Code 调试 Java 应用程序

对于使用 Visual Studio Code 的 Java 开发者来说,Language Support for Java(TM) by Red Hat 扩展提供了非常好的语言特性支持,比如智能感知和项目支持等.然而,我们也听到一些用户反馈需要调试 Java 程序.今天,我们万分激动地宣布,我们与 Red Hat 合作开发了能让开发者调试 Java 应用程序的轻量级扩展:Java Debugger for Visual Studio Code,它基于 Java Debug Server. 注意