正在运行的jmap无法打开套接字文件


85

我必须运行jmap才能进行进程的堆转储。但jvm返回:

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

所以我用了-F

./jmap -F -dump:format=b,file=heap.bin 10330
Attaching to process ID 10331, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.51-b03
Dumping heap to heap.bin ...
  1. 使用-F 可以进行堆转储吗?
  2. 我正在等待20分钟,尚未完成。有什么想法吗?

Answers:


181

jmapvs.jmap -F以及jstackvs.jstack -F使用完全不同的机制与目标JVM通信。

jmap / jstack

在没有-F这些工具的情况下运行时,请使用动态附加机制。其工作原理如下。

  1. 连接到Java进程1234之前,请在目标进程的工作目录或处jmap创建一个文件。.attach_pid1234/tmp

  2. 然后jmap发送SIGQUIT到目标进程。当JVM捕获信号并找到时.attach_pid1234,它将启动AttachListener线程。

  3. AttachListener线程创建UNIX域套接字/tmp/.java_pid1234以侦听来自外部工具的命令。

  4. 出于安全原因,当jmap接受(来自)连接时,JVM会验证套接字对等方的凭据euidegidJVM进程的凭据相同。这就是为什么jmap如果由其他用户(甚至由root用户)运行将无法正常工作的原因。

  5. jmap连接到套接字,并发送dumpheap命令。

  6. 该命令由AttachListenerJVM的线程读取和执行。所有输出都发送回插座。由于堆转储是由JVM直接在进程内进行的,因此操作速度非常快。但是,JVM只能在安全点执行此操作。如果无法达到安全点(例如,进程挂起,未响应或正在进行长时间的GC),jmap则将超时并失败。

让我们总结一下动态附加的优点和缺点。

优点

  • 堆转储和其他操作由JVM以最快的速度协同运行。
  • 您可以使用任何版本的jmapjstack连接到任何其他版本的JVM。

缺点

  • 该工具应由与目标JVM相同的用户(euid/ egid)运行。
  • 只能在实时且健康的JVM上使用。
  • 如果目标JVM以启动,则将无法使用-XX:+DisableAttachMechanism

jmap -F / jstack -F

使用-F工具运行时,切换到具有HotSpot Serviceability Agent的特殊模式。在这种模式下,目标进程被冻结;这些工具通过操作系统调试工具(即ptrace在Linux上)读取其内存。

  1. jmap -FPTRACE_ATTACH在目标JVM上调用。响应SIGSTOP信号无条件地暂停目标进程。

  2. 该工具使用读取JVM内存PTRACE_PEEKDATAptrace一次只能读取一个单词,因此读取目标进程的大堆需要太多调用。这非常非常慢。

  3. 该工具根据特定JVM版本的知识来重建JVM内部结构。由于不同版本的JVM具有不同的内存布局,因此-F只有jmap在与目标Java进程来自同一JDK的情况下,模式才有效。

  4. 该工具会自己创建堆转储,然后恢复目标进程。

优点

  • 不需要目标JVM的合作。即使在挂起的进程中也可以使用。
  • ptrace只要操作系统级别的特权就足够了,就可以使用。例如,root可以转储所有其他用户的进程。

缺点

  • 大堆非常慢。
  • 该工具和目标进程应来自相同版本的JDK。
  • 当工具以强制模式连接时,不能保证安全点。尽管jmap尝试处理所有特殊情况,但有时目标JVM可能不会处于一致状态。

注意

有一种更快的方法可以在强制模式下进行堆转储。首先,使用创建一个coredump gcore,然后jmap在生成的核心文件上运行。请参阅相关问题


84

我只是发现jmap(大概在使用jmapvm生成堆转储时大概是jvisualvm)强制执行jmap的用户必须与尝试转储进程的用户相同。

在我的情况下,我希望堆转储的JVM由Linux用户“ jboss”运行。所以在sudo jmap -dump:file.bin <pid>报告“无法打开套接字:”的地方,我能够使用以下方法获取堆转储:

sudo -u jboss jmap -dump:file.bin <pid>

我认为应该是\ -dump:file.bin <pid>,因为在将参数从sudo传递到jmap时需要转义-。
亚当

就是这个!您还需要对jmap和jcmd使用sudo。
xtian

哇..这确实有效。这应该是公认的答案
Lalit Rao

3

就像ben_wing所说的那样,您可以运行:

sudo -u jboss-as jmap -dump:file.bin <pid>

(在我的情况下,用户是jboss-as,但您的用户可能是jboss或其他。)

但这还不够,因为它要求我输入密码[sudo] password for ec2-user:),尽管我可以在sudo不使用其他命令提示输入密码的情况下运行。

我在这里找到了解决方案,我只需要再添加sudo一个:

sudo sudo -u jboss-as jmap -dump:file.bin <pid>

它与像其他的命令jcmdjinfo太。


加倍sudo保存我的一天!
Sher10ck

[root@v5 ~]# sudo sudo -u es jmap -dump:file=tmp.bin 26283 变成错误sudo: jmap: command not found。我已经在.bash_profile中配置了Java路径,该怎么办。
漫游

@roamer也许是因为当您以es用户身份运行时,.bash_profile未应用(因为bash配置文件与您的用户有关,我认为)。我建议,包括在一个更加全球化的方式java的路径,或者可能指定Java路径命令,像sudo sudo -u es PATH="$PATH:/java/path" jmap -dump:file=tmp.bin 26283(其中/java/path是java的路径,并确保它有jmap)。
卢卡斯·巴斯奎罗托

我在/home/es/.bash_profile中配置java路径,并且在以es用户身份登录时可以使用jmap。此cmdsudo sudo -u es /usr/java/jdk1.8.0_181-cloudera/bin/jmap -dump:file=tmp.bin 26283有效。非常感谢。
漫游

2

如果您的应用程序作为systemd服务运行。您应该打开服务文件,该文件位于/usr/lib/systemd/system/您的服务名称下并以您的服务名称命名。然后检查privateTmp属性是否为true。

如果为true,则应将其更改为false,然后按以下命令刷新服务: systemctl daemon-reload systemctl restart [servicename] 如果要在重新启动之前运行jmap / jcmd,则可以使用服务文件中的execStop脚本。只需将命令放入其中并执行systemctl stop [service name]


在更新/usr/lib/systemd/system/elasticsearch.service之前,将privateTmp设置为false,我得到以下错误:无法打开套接字文件:目标进程未响应或未加载HotSpot VM-即使我以
elasticsearch
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.