如何在JVM挂起的时候调试(翻译)

第一次翻译,大家凑合着看,英文好的请看原文:http://www.unixville.com/~moazam/stories/2004/05/18/debuggingHangsInTheJvm.html

在JVM挂起时调试线程

有时,JAVA用户或开发者会遇到JAVA应用程序看起来像挂起的问题,而且没有核心文件产生,没有任何的IO检测,这个过程只是坐在那里等待...通常这些问题可以追溯到操作系统和的JVM级别线程。

以下内容是从Solaris方面来介绍的,也许不久我会写些针对Linux线程的东西

两个线程模型的故事
Solaris 8和9有两个独立的线程模型。在sun的官方网站上有一个权威的解释 。点这里进入。我这边基本上长话短说, Solaris 8下,默认情况下,使用一个多对多线程模型,而Solaris 9采用了一对一线程模型。

在Solaris 9发布以后, Solaris 8还包括一对一线程模型作为'替代'的线程模型。用户如果想在Solaris 8使用"替代"的线程库,应当确保他们运行过最新的108993修补程序,早些时候反映此线程库有漏洞,后来采用上述补丁来修正。该线程模型的库是在/usr/lib/lwp下 。

当JAVA进程挂起时,你应该怎么做
在你的Java程序挂起时,有几个不同的事情,您可以尝试。

1.得到一个Java级别的堆栈跟踪。
2.获取当前LWPs(light weight process)和它们当前状态的快照
3.获得底层原生级别堆栈跟踪。
4.尝试对进程抛出SIGWAITING信号
5.强制进程dump一个core文件
6.切换到替代线程库,然后试着重现那个问题

下面更详细地说明每一个步骤..

1.得到一个Java级别堆栈跟踪。
这里的目的是从挂起进程中获得一个Java级别的堆栈跟踪。Java级别堆栈跟踪看起来如下所示:

可以从几个不同方式来介绍Java级别的堆栈跟踪。在UNIX环境中,您可以发送的进程SIGQUIT信号(kill -3 ,或kill -SIGQUIT ),然后进程将打印堆栈跟踪到控制台。在Windows中,你只能在启动这一进程的控制台按下Ctrl - /

如果您已使用用-Xrs参数来启动JVM,发送SIGQUIT和SIGWAITING信号将无效-Xrs参数的目的是告诉JVM忽视系统的信号。

为了记录进程的堆栈跟踪信息,您可以在启动JAVA程序时就重定向stdout和stderr到一个文件。

例如,要把jEdit程序的stderr和stdout重定向到一个叫"console.txt'的文件中,我们可以这样做:

java -jar jedit.jar > console.txt 2>&1

这个方法在Unix和Windows都适合 。

2.获取当前LWPs(light weight process)和它们当前状态的快照
本节旨在针对Solaris用户。很多人使用'top'或'prstat'来查看每个进程消耗了多少CPU,内存等。'prstat'命令允许用户查看在LWP级别,粒度更细的资源状况。只需运行'prstat -L'即可

prstat输出看起来像这样:

prstat -L output

从上面的输出,您可以看到,有一个Java的过程,但它有多个LWPs在运行。前两个( 13和10 )正消耗了6.1%和1.9%的CPU 。现在,当你接着往下看第三点的底层原生级别的堆栈跟踪,你将会明确知道某一个LWP正在做些什么

3.获得底层原生级别堆栈跟踪。
Solaris有一个非常有用的命令叫做'pstack' 。Linux用户也有福, 罗斯汤普森高人已经移植这个命令到Linux,你可以从这里下载 。

pstack命令能够根据指定的PID返回进程的调用过程。它显示了LWP的编号以及在pstack命令运行时的那时刻的系统调用信息。这对于检查为什么一个进程挂起或崩溃是有很大的帮助。

以下是底层原生堆栈跟踪,对应于上面的JAVA级别的堆栈跟踪。Java级别的跟踪显示了0x22nnid,对应十六进制是34 。我可以从上面的Java级别堆栈跟踪输出的前两行可以看出来。

"SideKick #1" prio=1 tid=0x00593b80 nid=0x22

因此,我们将在pstack输出内容中寻找LWP为34的。您可能还注意到,在'prstat -L'的输出中的第6行,里面的LWP也是LWP 34, 而它当前消耗了0.3%的CPU。

Native Stack for LWP 34

4.尝试对进程抛出SIGWAITING信号。

SIGWAITING游戏
第一件事是我建议大家在JAVA程序挂起时,尝试发送一个SIGWAITING信号给它。这是Solaris 8要求的,但你在Solaris 9下不需要这样做,因为它有一个不同的默认线程的行为。什么是SIGWAITING ?它是信号32,且它的定义是:

"A signal that is implemented in Solaris and used to tell a threaded process that it should consider creating a new LWP."

通常,当一个发生挂起时,一个LWP中有多个线程在调度,其中的一个被阻塞,而其他的可能仍然在运行。其他正在运行的线程可能就会变成孤魂野鬼,因为没有LWP可以依附。当SIGWAITING信号发送到挂起进程时,线程库将建立一个新的LWP,并重新调度那些"其他正在运行"的线程。可能会把原来挂起的进程救活。

5.强制一个进程dump一个core文件
如果上面所有的方法都不行的话,你也许需要在堆栈跟踪中进行更深层次的分析。而一个core文件将会指出哪些是导致进程挂起的。当一个进程处在挂起状态时,它不会自动dump出core文件。在Solaris上有一个名为'gcore'的命令,它能够强制一个处在任何状态的进程dump出core文件。使用简单, gcore

请确认您已在Solaris使用coreadmulimit命令开启core dump功能。

例如,想把使用全局唯一命名的core文件保存到/var/core/目录下,切换到root用户并使用下面命令:

mkdir -p /var/cores
coreadm -g /var/cores/%f.%n.%p.core -e global -e process -e global-setid -e proc-setid -e log

我个人认为,Java级别的堆栈跟踪,pstack的底层原生的堆栈跟踪,及prstat -L的输出数据已经足够了。因此core文件并不一定需要。

6.切换到替换线程库,并尝试重现该问题。
如果SIGWAITING信号确实帮助挂起的进程重新活过来,那么你运气不错。此时你应该切换到替换线程库,看看是否会重新出现挂起现象。一般来说,它不会再发生。

把你的应用程序切换到替换线程库是比较简单的,不需要重新编译。只需重置LD_LIBRARY_PATH环境变量以指向新的线程库。例如: LD_LIBRARY_PATH = / usr / lib中/ lwp LD_LIBRARY_PATH_64 = / usr/lib/lwp/64

You can find much more details about the alternate thread library and how to use it by reading this article, Alternate Thread Library (T2) -- New in the Solaris 8 Operating Environment

Nerd Note: Using the alternate thread library with Java

Some articles on the web have mentioned that only the LD_LIBRARY_PATH needs to be set to use the alternate thread library with Java. Other documents mention the -XX:+OverrideDefaultLibthread flag and state that it is required to attain the full benefits of the new thread library. The fact is, -XX:+OverrideDefaultLibthread is required on certain VM versions. The reason is that certain JVMs can not tell exactly which threading model the OS is using and can only be notified of the model via this flag. Depending on this flag, the internal behavior of certain versions of the VM did indeed change. The majority of VM versions being used do not require it, and do not need it, but it's much safer to add it in anyways. In the end, be on the safe side and just specify -XX:+OverrideDefaultLibthread if you want to use the alternate thread library in Solaris 8.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值