jvm 正在运行jmap获取无法打开套接字文件

amrnrhlw  于 2022-11-07  发布在  其他
关注(0)|答案(5)|浏览(204)

我必须运行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分钟了,还没有完成。你知道为什么吗?

mbskvtky

mbskvtky1#

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

jmap / jstack文件系统

在没有-F的情况下运行时,这些工具使用动态连接机制。其工作方式如下。
1.在连接到Java进程1234之前,jmap在目标进程的工作目录处或在/tmp处创建文件.attach_pid1234
1.然后jmap发送SIGQUIT给目标进程,JVM捕获到信号并找到.attach_pid1234后,启动AttachListener线程。

  1. AttachListener线程创建UNIX域套接字/tmp/.java_pid1234,以侦听来自外部工具的命令。
    1.出于安全原因,当连接(来自jmap)被接受时,JVM会验证套接字对等体的凭据是否等于JVM进程的euidegid。这就是为什么jmap在由不同的用户(甚至是root)运行时无法工作的原因。
  2. jmap连接到套接字,并发送dumpheap命令。
    1.此命令由JVM的AttachListener线程读取和执行。所有输出都被发送回套接字。由于堆转储是由JVM直接在进程内进行的,因此操作非常快。但是,JVM只能在safepoints时执行此操作。如果无法到达安全点(例如,进程挂起、不响应或正在进行长时间GC),jmap将超时并失败。
    让我们总结一下动态连接的优点和缺点。

优点

  • 堆转储和其他操作由JVM以最大速度协同运行。
  • 您可以使用任何版本的jmapjstack连接到任何其他版本的JVM。
    一致性
  • 该工具应由与目标JVM相同的用户(euid/egid)运行。
  • 只能在活动且正常的JVM上使用。
  • 如果目标JVM是以-XX:+DisableAttachMechanism启动的,则无法运作。

jmap -关闭/ jstack -关闭

当与-F一起运行时,工具会切换到具有HotSpot可维护性代理的特殊模式。在此模式下,目标进程被冻结;这些工具通过操作系统调试工具(即Linux上的ptrace)读取其内存。

  1. jmap -F调用目标JVM上的PTRACE_ATTACH,目标进程无条件挂起以响应SIGSTOP信号。
    1.该工具使用PTRACE_PEEKDATA读取JVM内存。ptrace一次只能读取一个字,因此需要太多的调用来读取目标进程的大堆。这非常非常慢。
    1.该工具基于对特定JVM版本的了解来重建JVM内部结构。由于不同版本的JVM具有不同的内存布局,因此-F模式仅在jmap与目标Java进程来自同一JDK时才有效。
    1.该工具会自行创建堆转储,然后恢复目标进程。

优点

  • 不需要目标JVM的配合。即使在挂起的进程上也可以使用。
  • ptrace在操作系统级别的权限足够的情况下工作。例如,root可以转储所有其他用户的进程。
    一致性
  • 对于大堆来说非常慢。
  • 该工具和目标进程应来自相同版本的JDK。
  • 当工具以强制模式连接时,无法保证安全点。虽然jmap尝试处理所有特殊情况,但有时可能会发生目标JVM不处于一致状态的情况。
    备注

有一个更快的方法可以在强制模式下进行堆转储。首先,用gcore创建一个核心转储,然后对生成的核心转储文件运行jmap。请参阅the related question

quhf5bfb

quhf5bfb2#

我刚刚发现jmap(大概还有jvisualvm在使用它生成堆转储时)强制要求运行jmap的用户必须是运行试图被转储的进程的同一个用户。
在我的例子中,我想要一个堆转储的JVM正由linux用户“jboss”运行。因此,在sudo jmap -dump:file.bin <pid>报告“无法打开套接字:“的地方,我能够使用以下命令获取我的堆转储:

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

hl0ma9xz3#

如果您的应用程序是以systemd服务执行。您应该开启/usr/lib/systemd/system/下的服务档,并以您的服务名称命名。然后检查**privateTmp**属性是否为true。
如果为true,则应将其更改为false,然后通过以下命令刷新服务:systemctl daemon-reload systemctl restart [servicename]如果你想在重新启动前运行jmap/jcmd,你可以使用服务文件中的execStop脚本。只需在其中放入命令并执行systemctl stop [service name]

waxmsbnn

waxmsbnn4#

正如ben_wing所说,您可以使用以下命令运行:

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

(in在我的情况下,用户是jboss-as,但您的用户可能是jboss或其他用户。)
但这还不够,因为它要求我输入密码[sudo] password for ec2-user:),尽管我可以用其他命令运行sudo而不提示我输入密码。
我找到了here的解决方案,我只需要先添加另一个sudo

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

它也可以与jcmdjinfo等其他命令一起使用。

w51jfk4q

w51jfk4q5#

通常用-F来解决。
如消息中所述:

The -F option can be used when the target process is not responding

我遇到了一种情况,即完整的GC使它无法执行命令。

相关问题