You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JVM应用内部调用jcmd/jmap生成类直方图时进程挂起问题

问题描述

我希望使用jmap或jcmd诊断意外的OOM错误,但这些工具在CI流水线中难以使用——需要后台启动JVM应用、获取其PID并把握时机才能得到有效结果。因此尝试在待诊断的JVM应用内部启动这些工具实现程序化自诊断,代码如下:

val process = ProcessBuilder("jcmd", getPID(), "GC.class_histogram")
    .redirectOutput(ProcessBuilder.Redirect.PIPE)
    .redirectError(ProcessBuilder.Redirect.PIPE)
    .start()

process.waitFor(2, TimeUnit.MINUTES)

但代码会导致jcmd和jmap均挂起,系统监控显示两者处于休眠状态;然而从外部对该休眠JVM执行jcmd 37058 GC.class_histogram却能立即得到预期的类直方图,请问这是什么原因?

原因分析与解决方案

这是因为JVM工具(jcmd/jmap)与目标JVM之间的通信依赖信号机制,而在JVM进程内部启动这些工具时,会触发进程内的信号处理阻塞:

  • 当从JVM内部启动jcmd并指向自身PID时,jcmd会向当前JVM发送SIGQUIT信号触发诊断操作。
  • 但当前JVM此时正处于process.waitFor()的阻塞状态,无法及时处理该信号——信号处理线程被主线程的阻塞逻辑卡住,导致jcmd一直等待目标JVM响应,最终双方都进入休眠挂起状态。
  • 从外部执行jcmd时,目标JVM没有被自身的进程等待逻辑阻塞,能正常处理信号并返回结果。

可行解决办法

  • 不要在主线程中执行等待逻辑:将启动jcmd和等待的逻辑放到单独的线程中执行,避免阻塞JVM的信号处理线程。
  • 换用JVM内置诊断API替代:比如使用java.lang.management包下的MemoryMXBean、ClassLoadingMXBean,直接在进程内获取内存、类加载数据,无需启动外部进程。
  • 若必须启动外部工具:启动后立即读取输出流和错误流,避免管道缓冲区满导致外部进程挂起(你的代码已做重定向,但读取操作不可省略)。

内容的提问来源于stack exchange,提问作者Martin Drozdik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 15:54:42