bigywater.tech
Java · 346

jhsdb:离线检查 JVM 进程状态

jhsdb 不是通过 JVM 内部的 attach 通道,而是从外面直接读目标进程的内存。这篇在真实进程上跑它,看输出多出了什么、对目标进程做了什么,以及 core 文件这条离线路径在这台机器上走不走得通。

12247 ms
jhsdb 退出后目标进程被停住、直到手工 SIGCONT 的时间(心跳线程的最大间隔)
2.45 s vs 0.08 s
jhsdb jmap --histo 与 jmap -histo 的耗时(结果一致)
Can't attach to the core file
这台 macOS 上 jhsdb jstack --core 读 3349 MB core 文件的结果

jhsdb jstack

实测 · 本机执行输出
  jhsdb jstack 耗时 1.27 s,输出 122 行;开头:
    Attaching to process ID 7961, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 21.0.12.1
    Deadlock Detection:
    
  Deadlock Detection 段落(节选):
    Found one Java-level deadlock:
    =============================
    
    "dl-1":
      waiting to lock Monitor@0x0000007c111257a0 (Object@0x000000012ed15ec8, a java/lang/Object),
      which is held by "dl-2"
    "dl-2":
      waiting to lock Monitor@0x0000007c11125880 (Object@0x000000012ed15eb8, a java/lang/Object),
      which is held by "dl-1"
  spin 线程(jhsdb jstack):
    "spin" #21 daemon prio=5 tid=0x0000007c10d6f100 nid=27395 runnable [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
       JavaThread state: _thread_in_java
     - Main.lambda$main$1() @bci=7, line=10 (Compiled frame; information may be imprecise)
     - Main$$Lambda+0x0000009801000c28.run() @bci=0 (Interpreted frame)
     - java.lang.Thread.runWith(java.lang.Object, java.lang.Runnable) @bci=5, line=1596 (Interpreted frame)
  dl-1 线程(jhsdb jstack):
    "dl-1":
      waiting to lock Monitor@0x0000007c111257a0 (Object@0x000000012ed15ec8, a java/lang/Object),
      which is held by "dl-2"

目标进程被停住

实测 · 本机执行输出
  jhsdb 退出后立即 ps 的进程状态: 'T' (S = 睡眠中,T = 被停住)
  3 秒后: 'T'
  此时 jcmd <pid> VM.uptime:8 秒内没有返回
  发送 SIGCONT 后: 'R'
  应用里的 5 ms 心跳线程的最大间隔(ms): GAP 12247 (从被停住到继续的总时长)
  SIGCONT 之后 jcmd <pid> VM.uptime: 7961: 14.221 s

jhsdb jmap

实测 · 本机执行输出
  jhsdb jmap --heap 耗时 0.98 s,48 行,节选:
    Garbage-First (G1) GC with 9 thread(s)
     MaxHeapSize = 268435456 (256.0MB)
     MetaspaceSize = 22020096 (21.0MB)
     MaxMetaspaceSize = 17592186044415 MB
     G1HeapRegionSize = 1048576 (1.0MB)
     capacity = 268435456 (256.0MB)
     used = 23101480 (22.031288146972656MB)
     8.605971932411194% used
     capacity = 24117248 (23.0MB)
     used = 19922944 (19.0MB)
     82.6086956521739% used
     capacity = 0 (0.0MB)
     used = 0 (0.0MB)
     0.0% used
     capacity = 244318208 (233.0MB)
     used = 3178536 (3.0312881469726562MB)
     1.3009820373273202% used
  jhsdb jmap --histo 耗时 2.45 s,354 行;其中 Main$Live: ['2: 200000 6400000 Main$Live']
    Attaching to process ID 7961, please wait...
    Debugger attached successfully.
    Server compiler detected.
  jmap -histo 里 Main$Live: [' 2: 200000 6400000 Main$Live'] (耗时 0.08 s)

clhsdb

实测 · 本机执行输出
  耗时 1.01 s;输出 165 行;节选:
    hsdb> Heap Parameters:
    garbage-first heap [0x000000011f000000, 0x000000012f000000] region size 1024K
    G1 Heap:
       regions  = 256
    G1 Young Generation:
       regions  = 19
       regions  = 0
    G1 Old Generation:
       regions  = 4
    hsdb> 4867 main
    Thread id: 4867
    Thread id: 29955
    Thread id: 29699
    Thread id: 29443
    29187 Service Thread
    Thread id: 29187
    28931 Monitor Deflation Thread
    Thread id: 28931
    25859 C2 CompilerThread0
    Thread id: 25859
    28419 C1 CompilerThread0
    Thread id: 28419
    26371 Notification Thread
    Thread id: 26371
    Thread id: 26627
    Thread id: 26883
    Thread id: 27395
    Thread id: 43267
    Thread id: 33283
    Thread id: 23819
    hsdb> Main @0x0000009801000800
    hsdb>

从 core 文件离线分析

实测 · 本机执行输出
  /cores 可写: True
  JVM 进程是否已退出: False ;退出码 None ;新出现的 core 文件: [('core.8092', 3349)] ;hs_err 文件: True
  jhsdb jstack --core(耗时 0.1 s):
    Attaching to core /cores/core.8092 from executable /opt/homebrew/Cellar/openjdk@21/21.0.12.1/libexec/openjdk.jdk/Contents/Home/bin/java, ple
    Error attaching to core file: Can't attach to the core file
    sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the core file
    	at jdk.hotspot.agent/sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal.attach0(Native Method)
    	at jdk.hotspot.agent/sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal.attach(BsdDebuggerLocal.java:268)
    	at jdk.hotspot.agent/sun.jvm.hotspot.HotSpotAgent.attachDebugger(HotSpotAgent.java:638)
    	at jdk.hotspot.agent/sun.jvm.hotspot.HotSpotAgent.setupDebuggerDarwin(HotSpotAgent.java:624)
    	at jdk.hotspot.agent/sun.jvm.hotspot.HotSpotAgent.setupDebugger(HotSpotAgent.java:372)

分步演示

jhsdb
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12(Homebrew),macOS 27 arm64,以普通用户身份(未用 sudo)attach;所有数字来自真实运行
    • 没有验证:Linux 上 jhsdb attach 之后目标是否会被自动恢复(这里的“退出后仍是 T”只在这台 macOS 上观察到)、Linux 上用 gdb / gcore 生成的 core 文件能否被 jhsdb --core 读取、jhsdb hsdb 图形界面、jhsdb 对容器内 JVM 与权限(ptrace)的要求、clhsdb 的其它命令(printmdo、whatis 等)
    京ICP备2026067502号-1京公网安备11010502063487号