在JVM性能监控的领域里JDK为我们提供了一系列强大的工具。其中jstat、jmap、jstack这三个工具就像是三位得力的助手帮助我们深入了解JVM的运行状态及时发现和解决性能问题。接下来我们就一起详细了解这三款工具的功能、使用方法以及相关的命令示例让你轻松掌握JVM性能监控的技巧。核心工具功能介绍jstat工具jstatJava Virtual Machine Statistics Monitoring Tool是用于监控虚拟机各种运行状态信息的工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。用大白话来讲jstat就像是一个“数据探测器”能帮我们查看JVM内部的各种运行数据。类装载信息监控可以查看类的加载、卸载数量以及类加载所耗费的时间等信息。例如通过查看类加载的时间我们可以判断是否存在类加载过慢的问题这可能是由于类路径配置不合理或者磁盘I/O性能不佳导致的。内存使用情况监控能够实时显示JVM各内存区域如堆内存、非堆内存的使用量和占用率等信息。通过监控内存使用情况我们可以及时发现内存泄漏或者内存溢出的潜在风险。垃圾收集统计信息监控可以获取垃圾收集的次数、时间以及各代内存区域的垃圾回收情况等信息。这有助于我们分析垃圾回收的效率判断是否需要调整垃圾回收策略。jmap工具jmapJava Memory Map主要用于生成堆转储快照也称为heap dump文件还可以查询finalize执行队列、Java堆和永久代的详细信息如空间使用率、当前使用的是哪种垃圾收集器等。简单来说jmap就像是一个“内存快照相机”能帮我们拍下JVM内存的当前状态。生成堆转储快照通过执行相应的命令jmap可以将JVM的堆内存状态以文件的形式保存下来。这个堆转储快照文件对于后续分析内存泄漏、内存溢出等问题非常有帮助。查看堆内存详细信息可以获取堆内存的使用情况、各代内存区域的大小和占用率等信息帮助我们了解JVM的内存分配情况。查看永久代信息在JDK 8及以前在JDK 8及以前的版本中jmap还可以查看永久代的相关信息包括永久代的大小、使用情况等。jstack工具jstackJava Stack Trace用于生成Java虚拟机当前时刻的线程快照。线程快照就是当前Java虚拟机内每一条线程正在执行的方法堆栈的集合生成线程快照的主要目的是定位线程出现长时间停顿的原因如线程死锁、死循环、请求外部资源导致的长时间等待等。可以把jstack想象成一个“线程侦探”帮我们找出线程运行中存在的问题。分析线程状态通过查看线程快照我们可以了解每个线程的当前状态如RUNNABLE运行中、WAITING等待、TIMED_WAITING限时等待等。这有助于我们分析线程的运行情况找出可能存在的问题。检测线程死锁jstack可以检测到线程之间是否存在死锁的情况。死锁是指两个或多个线程在执行过程中因争夺资源而造成的一种互相等待的现象会导致程序无法正常运行。通过jstack的输出我们可以快速定位到死锁的线程和相关的代码位置。实操演示常用命令示例jstat命令示例查看类加载信息jstat-classpid这里的pid是Java进程的ID。执行该命令后会显示类加载的数量、卸载的数量、类加载和卸载所耗费的时间等信息。例如Loaded Bytes Unloaded Bytes Time 1234 2345 10 20 1.23这表示已经加载了1234个类占用了2345KB的内存卸载了10个类卸载的类占用了20KB的内存类加载和卸载总共花费了1.23秒。查看垃圾收集信息jstat-gcpidintervalcountinterval表示统计信息输出的时间间隔单位为毫秒count表示输出的次数。例如执行jstat -gc 1234 1000 5表示每隔1000毫秒即1秒输出一次Java进程ID为1234的垃圾收集信息总共输出5次。输出信息示例如下S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 20480.0 20480.0 0.0 0.0 102400.0 40960.0 204800.0 30720.0 10240.0 8192.0 1024.0 819.2 10 0.123 2 0.234 0.357其中各列的含义如下S0C和S1C分别表示Survivor 0区和Survivor 1区的容量单位为KB。S0U和S1U分别表示Survivor 0区和Survivor 1区的使用量单位为KB。EC和EU分别表示Eden区的容量和使用量单位为KB。OC和OU分别表示老年代的容量和使用量单位为KB。MC和MU分别表示方法区元空间的容量和使用量单位为KB。CCSC和CCSU分别表示压缩类空间的容量和使用量单位为KB。YGC表示年轻代垃圾收集的次数。YGCT表示年轻代垃圾收集所耗费的总时间。FGC表示老年代垃圾收集的次数。FGCT表示老年代垃圾收集所耗费的总时间。GCT表示总的垃圾收集时间。jmap命令示例生成堆转储快照jmap-dump:formatb,fileheapdump.hprofpid该命令会将Java进程ID为pid的堆内存状态以二进制格式保存到heapdump.hprof文件中。生成的堆转储快照文件可以使用一些工具如Eclipse Memory Analyzer进行分析以找出内存泄漏等问题。查看堆内存详细信息jmap-heappid执行该命令后会输出堆内存的详细信息包括堆内存的使用情况、各代内存区域的大小和占用率、当前使用的垃圾收集器等信息。示例输出如下Attaching to process ID 1234, please wait... Debugger attached successfully. Server compiler detected. JVM version is 1.8.0_271 using thread-local object allocation. Parallel GC with 4 thread(s) Heap Configuration: MinHeapFreeRatio 0 MaxHeapFreeRatio 100 MaxHeapSize 2147483648 (2048.0MB) NewSize 5570560 (5.3125MB) MaxNewSize 715773952 (682.6171875MB) OldSize 11272192 (10.75MB) NewRatio 2 SurvivorRatio 8 MetaspaceSize 21807104 (20.796875MB) CompressedClassSpaceSize 1073741824 (1024.0MB) MaxMetaspaceSize 17592186044415 MB G1HeapRegionSize 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity 20635648 (19.680908203125MB) used 10485760 (10.0MB) free 10149888 (9.680908203125MB) 50.81373291925466% used From Space: capacity 5242880 (5.0MB) used 0 (0.0MB) free 5242880 (5.0MB) 0.0% used To Space: capacity 5242880 (5.0MB) used 0 (0.0MB) free 5242880 (5.0MB) 0.0% used PS Old Generation capacity 104857600 (100.0MB) used 31457280 (30.0MB) free 73400320 (70.0MB) 30.0% used 2222 interned Strings occupying 184016 bytes.jstack命令示例查看线程快照jstackpid执行该命令后会输出Java进程ID为pid的所有线程的当前状态和堆栈信息。示例输出如下2024-07-01 10:00:00 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.271-b09 mixed mode): Attach Listener #10 daemon prio9 os_prio0 tid0x00007f9d8c001000 nid0x2d03 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE DestroyJavaVM #1 prio5 os_prio0 tid0x00007f9d9000b800 nid0x2cfe waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE Thread-0 #2 prio5 os_prio0 tid0x00007f9d9000c800 nid0x2cff waiting on condition [0x00007f9d7c70e000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at com.example.MyClass$MyThread.run(MyClass.java:20) ...从输出信息中我们可以看到每个线程的ID、优先级、状态以及正在执行的方法堆栈等信息。通过分析这些信息我们可以找出线程运行中存在的问题如线程死锁、死循环等。总结与展望通过学习jstat、jmap、jstack这三款JDK自带的监控工具我们掌握了一种强大的JVM性能监控手段。jstat让我们可以实时监控JVM的各种运行数据jmap能帮助我们获取堆内存的详细信息和生成堆转储快照jstack则用于分析线程的运行状态和检测线程死锁。这些工具对于解决JVM性能问题、优化程序运行效率非常有帮助。掌握了这些工具的使用方法后下一节我们将深入学习其他JVM性能监控工具进一步完善对本章JVM性能监控工具主题的认知。让我们继续探索提升自己在JVM性能监控方面的技能。 系列专栏导航 《JVM调优》 博客概览《程序员技术成长导航专栏汇总》