JVM学习日记(十五)Day15——性能监控与调优(二)

发布于:2025-08-05 ⋅ 阅读:(21) ⋅ 点赞:(0)

好了我们这一篇继续来说命令行监控指令,上一篇说了4个比较重要的指令,其中用的比较多的也就是jstat和jmap了。

jhat:堆转储分析工具

他是JDK自带的分析工具,分析我们上一篇说的jmap转存的内存快照,​​内置了一个微型的HTTP服务器提供Web界面浏览分析结果(默认端口是7000),帮助识别内存泄漏和大对象,​同时支持OQL(Object Query Language)查询,但是已经在JDK9中被删除了,因为官方推荐使用VissualVM。

#基本语法
jhat [options] <heap-dump-file>

#基本用法
# 分析堆转储文件并在7000端口启动服务
jhat heap.hprof

# 访问分析结果
http://localhost:7000
参数 说明 示例
-stack false 关闭对象分配调用栈跟踪 jhat -stack false heap.hprof
-refs false 关闭对象引用跟踪 jhat -refs false heap.hprof
-port <port> 指定HTTP服务器端口(默认7000) jhat -port 8000 heap.hprof
-exclude <file> 指定排除文件(包含排除的类名) jhat -exclude exclude.txt heap.hprof
-baseline <file> 指定基准堆转储(用于比较) jhat -baseline base.hprof heap.hprof
-debug <int> 设置调试级别(0-2) jhat -debug 1 heap.hprof
-version 显示版本信息 jhat -version
-h/-help 显示帮助信息 jhat -help

 这个表示就已经启动成功了,可以去浏览器的http://localhost:8000/进行访问,这边建议小伙伴自己去尝试查看,知道这个东西就可以了,后面我们还是使用GUI图形界面去分析的,因为这个会更加的直观的。

jstack:生成 Java 进程的线程快照

我们上篇说到了jamp的堆快照,这里又有个可以查看线程的快照,因为程序出现卡顿不一定是堆堆问题嘛,也可能是线程的问题,jstack获取线程快照​:显示所有 Java 线程的调用栈信息,​诊断死锁​:自动检测并报告死锁线程,分析高 CPU 占用​:结合 top 或 jps 定位问题线程,排查线程阻塞​:识别等待资源或锁的线程。

#基本语法
jstack [options] <pid>
参数 作用 示例
-F 强制生成线程转储(当进程挂起时使用) jstack -F 1234
-l 显示额外锁信息(包含同步器和 java.util.concurrent 锁) jstack -l 1234
-m 混合模式(显示 Java 和本地方法栈) jstack -m 1234
-h/-help 显示帮助信息 jstack -help

 这里来说一下区别,和jmap不同的就是他不会要求生成文件然后再分析,而是直接把内容打印到控制台,当然也是可以存文件的,这个文件就是普通的txt文件不需要其他命令或者工具辅助查看了。

jstack -F 1234 > thread_dump.txt
#其实所有的输出都可以用这种方式存到指定的文件
#这个就是基本信息了
2025-08-01 17:13:34 //快照时间
Full thread dump Java HotSpot(TM) 64-Bit Server VM (21.0.5+9-LTS-239 mixed mode, emulated-client, sharing): //虚拟机信息

Threads class SMR info: //一共30个线程,线程的地址如下
_java_thread_list=0x0000600002111ac0, length=30, elements={
0x0000000127010a00, 0x0000000127011200, 0x0000000127011a00, 0x000000011680f600,
0x000000011680d000, 0x000000011680d800, 0x000000011680aa00, 0x00000001268b2c00,
0x00000001269abc00, 0x0000000117102800, 0x0000000126b09200, 0x0000000127333c00,
0x0000000126b1c000, 0x000000012723ec00, 0x0000000117200e00, 0x0000000126b0e000,
0x0000000117008e00, 0x000000012734f000, 0x000000012734f800, 0x0000000127346200,
0x0000000127346a00, 0x000000011721b800, 0x0000000126b36c00, 0x0000000126b3ec00,
0x0000000126b3f400, 0x0000000126b3fc00, 0x0000000127347200, 0x0000000126b40400,
0x0000000127344600, 0x0000000126820000
}

"Reference Handler" #9 [32259] daemon prio=10 os_prio=31 cpu=1.76ms elapsed=141885.62s tid=0x0000000127010a00 nid=32259 waiting on condition  [0x000000016ec6e000]
#"Reference Handler"​​:线程名称
​​#9​:线程序号(JVM内部编号)
#​​[32259]​​:原生线程ID(Native Thread ID)
#​daemon​:这是一个守护线程(非用户线程)
​#prio=10​:Java线程优先级(1-10)
​#os_prio=31​:操作系统线程优先级
​#cpu=1.76ms​:该线程累计使用的CPU时间
​#elapsed=141885.62s​:线程已运行的时间(秒)
​#tid=0x0000000127010a00​:Java线程ID(内存地址)
#​nid=32259​:对应的操作系统线程ID(Native ID)
​#waiting on condition​:线程当前状态
​​#[0x000000016ec6e000]​​:线程栈的起始地址

   java.lang.Thread.State: RUNNABLE//运行状态
	at java.lang.ref.Reference.waitForReferencePendingList(java.base@21.0.5/Native Method)
	at java.lang.ref.Reference.processPendingReferences(java.base@21.0.5/Reference.java:246)
	at java.lang.ref.Reference$ReferenceHandler.run(java.base@21.0.5/Reference.java:208)

线程状态(Thread.State)

  • RUNNABLE​:线程正在执行或准备执行
  • WAITING​:线程等待某个条件(通常需要唤醒)
  • BLOCKED​:线程等待获取锁
  • TIMED_WAITING​:线程在指定时间内等待

这个就是jstack的示例,这里说一下什么是 daemon​:守护线程(JVM退出时不等待这些线程)什么是非daemon​:用户线程(JVM会等待这些线程结束),简单来说守护线程就是系统后台线程比如日志监控、垃圾回收等。

jcmd:多功能命令行工具

怎么说呢这哥们就是一个缝合怪,除了不能替代jstat其余的基本上都可以替代了,感觉前面讲的是不是有点多余了。

jcmd [options] <pid|main class> <command> [arguments]
部分 含义 是否必须 示例
jcmd 命令本身 必须 jcmd
[options] 全局选项 可选 -l-f
<pid|main class> 目标进程标识 必须 1234 或 com.example.MyApp
<command> 要执行的诊断命令 可选 Thread.printGC.heap_dump
[arguments] 命令参数 可选 filename=/tmp/dump.hprof
命令 作用 示例
VM.flags 查看JVM参数 jcmd 1234 VM.flags
VM.system_properties 查看系统属性 jcmd 1234 VM.system_properties
VM.uptime 显示JVM运行时间 jcmd 1234 VM.uptime
VM.version 显示JVM版本 jcmd 1234 VM.version
Thread.print 生成线程转储 jcmd 1234 Thread.print
GC.class_histogram 显示类直方图 jcmd 1234 GC.class_histogram
GC.heap_dump 生成堆转储文件 jcmd 1234 GC.heap_dump /path/to/dump.hprof
GC.run_finalization 强制执行finalize jcmd 1234 GC.run_finalization
GC.run 显式触发GC jcmd 1234 GC.run
JFR.start 开始JFR记录 jcmd 1234 JFR.start name=myrec settings=profile
JFR.dump 导出JFR记录 jcmd 1234 JFR.dump name=myrec filename=rec.jfr
JFR.stop 停止JFR记录 jcmd 1234 JFR.stop name=myrec
VM.native_memory 本地内存统计 jcmd 1234 VM.native_memory summary

 突然感觉这个命令有点复杂了有木有,主包这边就不演示了,这么多参数和命令又点头疼,具体使用什么命令还是要看小伙伴自己和使用的场景,有兴趣的小伙伴自己去试试看吧。

jstatd:远程监控工具

作用就是为远程主机提供 JVM 监控数据,通过 RMI 协议提供监控数据,可同时监控多个 Java 进程,支持 VisualVM、JConsole 等工具连接,这个咱们就简单说一下就好了,因为大多数生成环境是不允许的,多开一个端口都是有风险的。

#基本语法
jstatd [options]
#实例
jstatd -J-Djava.security.policy=jstatd.policy -p 3333
参数 作用 示例
-p <port> 指定 RMI 注册端口 jstatd -p 1099
-n <name> 指定 RMI 注册名称 jstatd -n MyJstatd
-J<option> 传递参数给 JVM jstatd -J-Djava.security.policy=my.policy
-nr 不创建 RMI 注册表 jstatd -nr
-r <port> 指定 RMI 注册表端口 jstatd -r 1099
-h/-help 显示帮助信息 jstatd -h

 总结

本篇把剩下的命令行已经全部介绍完了,下一篇讲讲GUI图形界面,大家好好练习命令吧。


网站公告

今日签到

点亮在社区的每一天
去签到