jstack - 著名文件不安全

54

我在x86_64 CentOS 5.7上运行tomcat 5.5,使用32位的Oracle Java 1.6.0。JVM进程使用pid为6421。Tomcat运行正常。

当运行jstack时,它会失败并显示如下信息:

[root@mybox ~]# jstack 6421
6421: well-known file is not secure
为了得到任何合理的输出,我需要使用force选项:
[root@mybox ~]# jstack -F 6421
Attaching to process ID 6421, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 17.0-b16
Deadlock Detection:

No deadlocks found.
(...)

问题如下:

  1. 错误信息“well-known file is not secure”的含义是什么?
  2. “well-known”文件是什么?
  3. 为什么/在什么情况下,jstack命令没有force选项就无法工作?

感谢您的帮助。


Tomcat运行了多长时间?CentOS / RHEL会在几天后(我忘记了具体是多久)不帮助删除/tmp中的文件。 - Paul Cager
@PaulCager:在运行jstack前大约1分钟我重新启动了。 - Michał Šrajer
1
同样适用于运行jmap执行堆转储。 - Nicolas
11个回答

39

这可能是由于用于与进程通信的/tmp文件具有不同的权限,导致 jstack 获取的文件不同。涉及到的文件是 /tmp/hsperfdata_$USER/$PID。

不知道为什么使用-F可以正常工作,因为man页面只是说“当'jstack [-l] pid'没有响应时强制进行堆栈转储。”


7
我曾经遇到过同样的问题,因为我的组与hsperfdata*文件所在的组不同。通过使用"newgrp other-group"命令更改我的组解决了这个问题。 - Stefan Birkner
我正在以root身份运行。运行jstack或jcmd仍然打印相同的消息。有一个名为/tmp/hsperfdata_root/pid的文件夹,它是可访问的。 - dmachop
6
运行jstack命令的uid:gid必须与知名文件的uid:gid相匹配。以root身份运行不会覆盖此检查 - 您可以通过sudo -u youruser -g yourgroup jstack ...来变成正确的uid:gid。 - Nick
实际上,它是/tmp/.java_pid<pid> - Danny Thomas

27

当使用-F时,jvm将被冻结

如果您能够找到file: /tmp/hsperfdata_$USER/$PID。尝试切换到$USER,然后执行jstack命令。您正在使用“root”运行,但该进程可能不属于root。

如果$USER没有登录Shell(即守护程序用户)因此无法切换到该用户,则可以通过使用sudo -u $USER jstack $PID来解决此问题。


12
如果$USER没有登录Shell(例如,守护程序用户)因此无法切换到该用户,则可以通过使用sudo -u $USER jstack $PID来解决此问题。请注意,这不会改变原始意思。 - László van den Hoek

7

我试图以root权限运行jstack时遇到了问题。

一旦我切换到另一个用户,它就立即正常工作了。


1
是的,这对我有用。将我的应用程序(jvmtop)作为与Java进程相同的用户运行,错误消息和故障就消失了... - rogerdpack

6

您需要用拥有Java进程的用户身份运行jstack命令:

例如,如果您的Java应用程序的所有者是名为java-user的用户:

sudo -u java-user jstack -l <pid> 

4

我只想补充一点,你可能需要使用-J选项指定您的/tmp目录,因为并不是所有应用程序都使用默认目录。

jstack -J-Djava.io.tmpdir=PATH -l PID

2

我运行时遇到了相同的错误:

watch -n .5 "jstack 26259"

以sudo身份运行可以解决问题:

sudo watch -n .5 "jstack 26259"

1
如果您不想担心用户,并且可以作为根用户工作并且可以终止进程,那么您可以使用这个最后的手段:
kill -s SIGQUIT $PID

这将把线程转储写入您的控制台日志中,例如,在Tomcat的情况下,需要在logs/catalina.out中搜索"Full Thread",这是线程转储的开头,然后获取tdump文件:
DUMP_IDX=`grep -n 'Full thread' logs/catalina.out | tail -1 | cut -d':' -f1`
sed -n $DUMP_IDX,1000000000000000000p logs/catalina.out > jstack-kill-thread-dump-0309.tdump

0

这是我用来确保始终使用正确用户权限的一行代码:

proc="my-process-name"; pid=`pgrep -f "${proc}"`; sudo -u "#`ps axo uid,pid | grep "${pid}" | tr -s " " | cut -f2 -d" "`" /usr/bin/jstack -l "${pid}" > /mnt/dumps/"${proc}"-`date +%s`.txt

0
除了使用相同的用户运行之外,确保运行 jstack/jmap 的用户组 ID 与进程也相同。
看一下 检查文件权限的源代码(第 347 行)。我们可以看到获取组 ID 的函数不是一个数组,因此可能存在用户有其他启动该进程的组。
您可能需要更改用户的主要组: #usermod -g group -G user user

-1

可能最简单的方法是:

通过 ps -ef | grep "进程名" 命令查看进程所有者,

然后切换到该用户并运行命令。

使用 jcmd PID GC.run 或其他 Java 实用程序。

还有一件事没人在这里讨论,那就是:您还需要设置 JAVA_HOME 变量。通过 echo $JAVA_HOME 检查它。


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