我必须运行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 ...
-F
可以进行堆转储吗?答案 0 :(得分:136)
jmap
与jmap -F
以及jstack
与jstack -F
使用完全不同的机制与目标JVM进行通信。
在没有-F
的情况下运行时,这些工具会使用Dynamic Attach Mechanism。其工作原理如下。
在连接到Java进程1234之前,jmap
在目标进程的工作目录或.attach_pid1234
创建文件/tmp
。
然后jmap
将SIGQUIT
发送到目标进程。当JVM捕获信号并找到.attach_pid1234
时,它会启动AttachListener
线程。
AttachListener
线程创建UNIX域套接字/tmp/.java_pid1234
以侦听来自外部工具的命令。
出于安全原因,当接受连接(来自jmap
)时,JVM会验证套接字对等方的凭据是否等于JVM进程的euid
和egid
。这就是为什么jmap
如果由不同的用户(甚至是root用户)运行将无法工作的原因。
jmap
连接到套接字,并发送dumpheap
命令。
此命令由JVM的AttachListener
线程读取并执行。所有输出都被发送回套接字。由于堆转储是由JVM直接在进程中进行的,因此操作非常快。但是,JVM只能在safepoints执行此操作。如果无法达到安全点(例如,进程挂起,未响应或正在进行长GC),jmap
将超时并失败。
让我们总结动态附加的好处和缺点。
<强>赞成。强>
jmap
或jstack
连接到任何其他版本的JVM。<强>缺点。强>
euid
/ egid
)作为目标JVM运行。-XX:+DisableAttachMechanism
启动,则无效。使用-F
运行时,工具会切换到功能HotSpot Serviceability Agent的特殊模式。在此模式下,目标进程被冻结;这些工具通过操作系统调试工具读取其内存,即Linux上的ptrace
。
jmap -F
在目标JVM上调用PTRACE_ATTACH
。目标流程无条件暂停,以响应SIGSTOP
信号。
该工具使用PTRACE_PEEKDATA
读取JVM内存。 ptrace
一次只能读取一个单词,因此读取目标进程的大堆需要太多调用。这非常非常慢。
该工具基于特定JVM版本的知识重建JVM内部结构。由于不同版本的JVM具有不同的内存布局,因此-F
模式仅在jmap
来自与目标Java进程相同的JDK时才有效。
该工具自己创建堆转储,然后恢复目标进程。
<强>赞成。强>
ptrace
就可以运行。例如。 root
可以转储所有其他用户的进程。<强>缺点。强>
jmap
尝试处理所有特殊情况,但有时可能会发生目标JVM未处于一致状态。注意强>
有一种更快的方法可以在强制模式下进行堆转储。首先,使用gcore
创建一个coredump,然后在生成的核心文件上运行jmap
。请参阅the related question。
答案 1 :(得分:72)
我刚刚发现jmap(当使用它来生成堆转储时可能是jvisualvm)强制运行jmap的用户必须是运行尝试转储的进程的用户。
在我的情况下,我希望堆转储的jvm由linux用户“jboss”运行。所以在sudo jmap -dump:file.bin <pid>
报告“无法打开套接字:”的情况下,我能够使用以下方式获取堆转储:
sudo -u jboss jmap -dump:file.bin <pid>
答案 2 :(得分:1)
如果您的应用程序作为systemd服务运行。应打开/usr/lib/systemd/system/
下并以服务名称命名的服务文件。然后检查 privateTmp 属性是否为真。
如果为true,则应将其更改为false,然后按以下命令刷新服务:
systemctl daemon-reload
systemctl restart [servicename]
如果要在重新启动之前运行jmap / jcmd,则可以使用服务文件中的execStop脚本。只需将命令放入其中并执行systemctl stop [service name]
答案 3 :(得分:1)
通常用 -f 解决。
我遇到过full GC导致命令无法执行的情况。
答案 4 :(得分:0)