运行jmap时出现“无法打开套接字文件”的错误

102

为了对我的进程进行堆转储,我不得不运行 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分钟还没有完成。有什么想法原因吗?
5个回答

230

jmapjmap -F,以及 jstackjstack -F 使用完全不同的机制来与目标JVM进行通信。

jmap / jstack

当没有使用 -F 参数时,这些工具使用动态附加机制。其工作原理如下:

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

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

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

  4. 出于安全考虑,当接受到一个连接(来自 jmap)时,JVM验证套接字对等方的凭据是否等于JVM进程的 euidegid。这就是为什么即使以root身份运行,jmap 也不能由不同的用户运行的原因。

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

  • 这个命令由JVM的AttachListener线程读取并执行。所有输出都发送回套接字。由于堆转储是直接由JVM在进程内完成的,所以操作速度非常快。但是,JVM只能在安全点进行此操作。如果无法到达安全点(例如进程挂起,无响应或正在进行长时间的GC),jmap将超时并失败。

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

    优点。

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

    缺点。

    • 该工具应由与目标JVM相同的用户(euid/egid)运行。
    • 只能用于活动且健康的JVM。
    • 如果目标JVM使用-XX:+DisableAttachMechanism启动,则无法正常工作。

    jmap -F / jstack -F

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

    1. jmap -F命令在目标JVM上调用PTRACE_ATTACH。目标进程将无条件地暂停,以响应SIGSTOP信号。

    2. 该工具使用PTRACE_PEEKDATA读取JVM内存。由于ptrace每次只能读取一个字,因此需要太多的调用才能读取目标进程的大堆。这是非常缓慢的。

    3. 该工具根据特定JVM版本的知识重构JVM内部结构。由于不同版本的JVM具有不同的内存布局,因此只有当jmap来自与目标Java进程相同的JDK时,-F模式才能正常工作。

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

    优点:

    • 无需目标JVM的协助。甚至可以在挂起的进程上使用。
    • ptrace只要拥有操作系统级别特权就可以工作。例如,root可以转储所有其他用户的进程。

    缺点:

    • 对于大堆来说速度非常慢。
    • 该工具和目标进程应该来自JDK的相同版本。
    • 在工具以强制模式附加时,不能保证安全点。虽然jmap尝试处理所有特殊情况,但有时可能会发生目标JVM不处于一致状态的情况。

    注意:

    以强制模式获取堆转储的更快方法是:首先使用gcore创建一个核心转储文件,然后在生成的核心文件上运行jmap。请参见相关问题


    90

    我刚刚发现jmap(以及使用它生成堆转储的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时,需要转义 -。 - adam
    这就是了!你也需要使用sudo来运行jmap和jcmd。 - xtian
    哇.. 这真的起作用了。这应该是被接受的答案。 - Lalit Rao
    我在使用jcmd时遇到了同样的问题,这个解决方案也对那里有所帮助。但是我不得不打开两个地图才能使它工作。这就是我最终得出的结果:sudo chmod 777 /proc/54321/cwd/ sudo chmod 777 /proc/54321/root/tmp/ sudo -u tomcat jcmd 54321 GC.heap_dump /tc/logs/heap_dump.hprof - Eelco

    6

    如果您的应用程序作为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 用户身份运行 jmap。 - imdibiji

    5

    就像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
    @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)。 - Lucas Basquerotto
    我在/home/es/.bash_profile中配置了Java路径,当以es用户登录时,我可以使用jmap。 这个命令sudo sudo -u es /usr/java/jdk1.8.0_181-cloudera/bin/jmap -dump:file=tmp.bin 26283有效。非常感谢。 - roamer

    1
    通常可以使用-F来解决。
    如消息中所述:
    The -F option can be used when the target process is not responding
    

    我遇到了一种情况,即Full GC使得命令无法执行。

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