jstack:目标进程无响应

52

我正在运行Ubuntu服务器版,想要获取Tomcat的线程转储。

因此,我首先尝试查找Tomcat使用的PID:

$ jps -l
5809 sun.tools.jps.Jps

但是它不在那里?

所以,我使用了top,发现PID为5730。

然后我调用jstack获取线程转储:

$ sudo jstack -l 5730
5730: Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding

发生了什么事?:-(

我已经按照Jstack和Jstat在升级到JDK6u23后停止工作中所述尝试导出CATALINA_TMPDIR,但这并没有改变任何事情:

$ export CATALINA_TMPDIR=/tmp
$ sudo /etc/init.d/tomcat6 restart
 * Stopping Tomcat servlet engine tomcat6
   ...done.
 * Starting Tomcat servlet engine tomcat6
   ...done.
$ sudo jstack -l 5934 // new PID after restart
5934: Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding

更新:

我还尝试了sudo -u tomcat6 jstack -l -F 5730 > threaddumpexceptions2.txt,但它只在控制台上给了我大量的异常信息。


1
你尝试过使用-F选项吗? - Michael Pigg
@Michael 如果我使用-F选项,那么它实际上会开始线程转储,但是转储本身只包含大量的错误消息:http://dl.dropbox.com/u/17844821/zeug/threaddump.txt,在转储过程中会抛出许多异常:http://dl.dropbox.com/u/17844821/zeug/threaddumpexception.txt - Timo Ernst
@valmar 你确定Tomcat使用的JDK和你用于JPS的JDK不是不同的JDK吗?你能再确认一下吗? - Clark Bao
@Clark Mh,我该怎么做? - Timo Ernst
@valmar请查看这个链接。http://www.howtogeek.com/howto/linux/installing-tomcat-6-on-ubuntu/ Tomcat依赖JAVA_HOME。但是在命令行中,您可以键入java -version来查看它们是否是相同的版本,并检查命令使用的java bin路径。 - Clark Bao
显示剩余8条评论
10个回答

78

我通过两个步骤使它起作用:

  1. 更改了调用方式:sudo -u tomcat6 jstack -J-d64 -m pid
  2. 用 Sun 原版的 sun-6-jdk 和 sun-6-jre 包替换了 OpenJDK

第一部分的解释:我切换到 64 位模式,使用 sudo 并以 Tomcat 用户身份运行命令。

注意:对于某些用户来说,第二部分可能不是必需的。实际上,首先尝试添加 sudo 命令。它可能已经奏效了。


34
对我来说,将“sudo -u <javaProcUsername>”放在命令前解决了我的问题。 - Jono
4
顺便说一下 - 我发现只要以相同的用户身份运行,我就可以消除这个错误 - 在我的情况下是尝试连接yourkit时出现的错误,但我认为同样的原则也适用。对于我来说,使用Sun JDK与OpenJDK之间或者指定64位与32位之间似乎并不必要来解决它。 - David W
1
使用与运行jvm相同的用户运行jstack命令,解决了我的问题。感谢@DavidW! - Andy Dufresne
-J-d64 根目录对我很有帮助,我尝试了每种组合,正确的用户、sudo、root。使用和不使用本地框架(-m),但当我加上 -J-d64 标志时它开始工作了,我还需要 -F 来解决进程无响应的问题。 - feldoh
切换到Tomcat用户后,-F标志实际上导致了失败。 - Alkanshel

34

我认为你需要使用与运行Tomcat进程相同的用户来运行jstack。注意,jps仅返回当前用户的进程。你可以通过使用sudo或Tomcat进程用户来运行jps以获取Tomcat进程的pid。

这个bug报告也可能会有所帮助: https://bugs.launchpad.net/ubuntu/+source/sun-java6/+bug/597098


我无法切换到tomcat6用户,因为它实际上不是系统上的“真实”Unix帐户。所以su tomcat6无法工作。 我刚刚尝试了sudo jps -l,但它仍然只给出6493 sun.tools.jps.Jps - Timo Ernst
我还尝试了 sudo -u tomcat6 jstack -l -F 5730 > threaddumpexceptions2.txt,但它只在控制台上给了我大量的异常:http://dl.dropbox.com/u/17844821/zeug/threaddump2.txt - 线程转储本身看起来像这样:http://dl.dropbox.com/u/17844821/zeug/threaddumpexceptions2.txt - 对我来说看起来不对。 - Timo Ernst
@valmar:尝试以下步骤以成为tomcat6:切换到root用户: sudo su - 从root用户,您可以切换到任何用户 su tomcat6 - Grey Panther
@Cd-MaN 没有效果。如果我这样做,它会给我这个(斜杠代表换行,因为我不能在评论中发布换行符):`$ whoami // valmar // $ sudo su - //

whoami //

root //

su tomcat6 //

whoami //

root`
- Timo Ernst
2
@valmar: 这可能意味着您为给定用户(tomcat6)没有设置shell,或者更准确地说,您将shell设置为像/bin/false这样的内容。要解决此问题,请在root帐户下使用 su -p tomcat6 命令(这将保留当前shell)。 - Grey Panther

4

不行,那没起作用。当我这样做时,什么都没有发生。 - Timo Ernst
1
如果您正在使用64位,则需要使用jstack -J-d64 -m pid,并尝试添加sudo -u tomcat6。http://download.oracle.com/javase/6/docs/technotes/tools/share/jstack.html - Clark Bao
哦,那只是在控制台上给了我一堆异常:http://dl.dropbox.com/u/17844821/zeug/console64.txt - Timo Ernst
1
如果我是你,我会尝试使用另一个JDK而不是OpenJDK。也许是因为OpenJDK的原因。 - Clark Bao
有趣。我用sun-java6-jre替换了openjdk-6-jre,现在jstack似乎可以正常工作了。 但是jps仍然没有显示tomcat和它的PID。 @Clark感谢您迄今为止的帮助!如果您将替换JRE的建议发布为新的、单独的答案,我会将其标记为“正确答案”。 - Timo Ernst

3

尝试切换到进程用户,然后使用jstack:

sudo -u {进程用户} jstack > dump


1

如果您是Tomcat用户,并遇到此问题,请检查catalina.out日志文件。

我曾经遇到同样的问题:“22693:无法打开套接字文件:目标进程未响应或HotSpot VM未加载”。我放弃了,试图找出在它锁定之前发生了什么事情,但是日志文件中有jstack输出。


1
我发现使用类似于“ps -eo pid,user,command | grep java”这样的命令很有用,可以找到实际使用的Java命令,然后使用该目录找到相应的jstack等工具。
# ps -eo user,command | grep '[j]ava' | cut -d' ' -f1
someuser /usr/lib/jvm/java/bin/java

# /usr/lib/jvm/java/bin/java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)

所以它是64位的,以“someuser”身份运行。切换到该用户并从相同的目录运行jstack等命令(即/usr/lib/jvm/java/bin/jstack)。当您在具有各种不同Java安装/实现的服务器上时非常有用。

1

这个方法对我也有效:

sudo -u tomcat6 kill -3 pid

看起来好像没有发生任何事情,但当你查看日志时,堆栈信息已经记录在那里了。如果你没想到它们,它们看起来像异常。


0

我遇到了同样的问题,但是以下任何解决方案都对我不起作用:

jstack <pid>
jstack -J-d64 -m <pid>
sudo -u <user> jstack ...

我终于将JDK从jdk1.6.0_24升级到jdk1.7.0_67,一切都正常工作了。


0

对于那些在六年后查看此答案并且使用的是CentOS 7的用户,请注意SELinux会阻止jmap写入堆转储文件,因为默认情况下,除非目录类型为tomcat_tmp_t,否则它将拒绝向套接字写入。

在我的情况下,我将我的堆转储文件写在/usr/share/tomcat/.jmap目录下。该目录归我的运行时用户所有。

因此,要允许jmap写入此目录:

semanage fcontext -a -t tomcat_tmp_t "/usr/share/tomcat/.jmap(/.*)?"
restorecon /usr/share/tomcat -vR

这使得我们可以作为我们的Tomcat用户运行:

jmap -dump:format=b,file=/usr/share/tomcat/.jmap/tomcat-`date +%s`.bin <pid>

0

我的问题是,我通过终端运行了这个进程。然后为了测试它的jstack,我用ctrl+z暂停了进程。但是进程无法响应。为了解决这个问题,我用另一个终端通过fg恢复了进程,并检查了它的jstack。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接