我必须运行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
进行堆转储是否合适?
1.我已经等了20分钟了,还没有完成。你知道为什么吗?
5条答案
按热度按时间mbskvtky1#
jmap
与jmap -F
,以及jstack
与jstack -F
使用完全不同的机制与目标JVM通信。jmap / jstack文件系统
在没有
-F
的情况下运行时,这些工具使用动态连接机制。其工作方式如下。1.在连接到Java进程1234之前,
jmap
在目标进程的工作目录处或在/tmp
处创建文件.attach_pid1234
。1.然后
jmap
发送SIGQUIT
给目标进程,JVM捕获到信号并找到.attach_pid1234
后,启动AttachListener
线程。AttachListener
线程创建UNIX域套接字/tmp/.java_pid1234
,以侦听来自外部工具的命令。1.出于安全原因,当连接(来自
jmap
)被接受时,JVM会验证套接字对等体的凭据是否等于JVM进程的euid
和egid
。这就是为什么jmap
在由不同的用户(甚至是root)运行时无法工作的原因。jmap
连接到套接字,并发送dumpheap
命令。1.此命令由JVM的
AttachListener
线程读取和执行。所有输出都被发送回套接字。由于堆转储是由JVM直接在进程内进行的,因此操作非常快。但是,JVM只能在safepoints时执行此操作。如果无法到达安全点(例如,进程挂起、不响应或正在进行长时间GC),jmap
将超时并失败。让我们总结一下动态连接的优点和缺点。
优点
jmap
或jstack
连接到任何其他版本的JVM。一致性
euid
/egid
)运行。-XX:+DisableAttachMechanism
启动的,则无法运作。jmap -关闭/ jstack -关闭
当与
-F
一起运行时,工具会切换到具有HotSpot可维护性代理的特殊模式。在此模式下,目标进程被冻结;这些工具通过操作系统调试工具(即Linux上的ptrace
)读取其内存。jmap -F
调用目标JVM上的PTRACE_ATTACH
,目标进程无条件挂起以响应SIGSTOP
信号。1.该工具使用
PTRACE_PEEKDATA
读取JVM内存。ptrace
一次只能读取一个字,因此需要太多的调用来读取目标进程的大堆。这非常非常慢。1.该工具基于对特定JVM版本的了解来重建JVM内部结构。由于不同版本的JVM具有不同的内存布局,因此
-F
模式仅在jmap
与目标Java进程来自同一JDK时才有效。1.该工具会自行创建堆转储,然后恢复目标进程。
优点
ptrace
在操作系统级别的权限足够的情况下工作。例如,root
可以转储所有其他用户的进程。一致性
jmap
尝试处理所有特殊情况,但有时可能会发生目标JVM不处于一致状态的情况。备注
有一个更快的方法可以在强制模式下进行堆转储。首先,用
gcore
创建一个核心转储,然后对生成的核心转储文件运行jmap
。请参阅the related question。quhf5bfb2#
我刚刚发现jmap(大概还有jvisualvm在使用它生成堆转储时)强制要求运行jmap的用户必须是运行试图被转储的进程的同一个用户。
在我的例子中,我想要一个堆转储的JVM正由linux用户“jboss”运行。因此,在
sudo jmap -dump:file.bin <pid>
报告“无法打开套接字:“的地方,我能够使用以下命令获取我的堆转储:hl0ma9xz3#
如果您的应用程序是以systemd服务执行。您应该开启
/usr/lib/systemd/system/
下的服务档,并以您的服务名称命名。然后检查**privateTmp**属性是否为true。如果为true,则应将其更改为false,然后通过以下命令刷新服务:
systemctl daemon-reload systemctl restart [servicename]
如果你想在重新启动前运行jmap/jcmd,你可以使用服务文件中的execStop脚本。只需在其中放入命令并执行systemctl stop [service name]
waxmsbnn4#
正如ben_wing所说,您可以使用以下命令运行:
(in在我的情况下,用户是
jboss-as
,但您的用户可能是jboss
或其他用户。)但这还不够,因为它要求我输入密码(
[sudo] password for ec2-user:
),尽管我可以用其他命令运行sudo
而不提示我输入密码。我找到了here的解决方案,我只需要先添加另一个
sudo
:它也可以与
jcmd
和jinfo
等其他命令一起使用。w51jfk4q5#
通常用-F来解决。
如消息中所述:
我遇到了一种情况,即完整的GC使它无法执行命令。