JVM 性能调优 -- JVM常用调优工具【jps、jstack、jmap、jstats 命令】

前言:

前面我们分析怎么去预估系统资源,怎么去设置 JVM 参数以及怎么去看 GC 日志,本篇我们分享一些常用的 JVM 调优工具,我们在进行 JVM 调优的时候,通常需要借助一些工具来对系统的进行相关分析,从而确定当前的 JVM 是否需要进行调优,以及有哪些问题需要优化。

JVM 系列文章传送门

初识 JVM(Java 虚拟机)

深入理解 JVM(Java 虚拟机)

一文搞懂 JVM 垃圾回收(JVM GC)

深入理解 JVM 垃圾回收算法

一文搞懂 JVM 垃圾收集器

JVM 调优相关参数

JVM 场景面试题【强烈推荐】

JVM 性能调优 -- 线上应用 JVM 内存的的预估设置【实战】

JVM 性能调优 -- 线上应用 JVM 内存调优【实战】

JVM 性能调优 -- 模拟触发 Minor GC【GC 日志分析】

JVM 性能调优 -- 模拟触发 Minor GC(2)【GC 日志分析】

JVM 性能调优 -- CMS 垃圾回收器 GC 日志分析【Full GC】

JVM 调优工具认识

辅助 JVM 调优的工具有很多种,从宏观上我们可以分为两类,分别是 Java 自带的相关工具和第三方辅助调优工具,本篇我们只讨论 Java 自带的 JVM 调优工具。

JVM 自带的调优工具又可以分为两类,如下:

命令行工具

  • jps:查看进程的信息。
  • jinfo:查看进程基本信息,包括启动参数、垃圾回收器等信息。
  • jstack:查看 Java 进程的线程的堆栈信息。
  • jmap:主要用于生成堆转内存快照。
  • jhat:JVM 堆转储快照分析工具,一般和 jmap 结合使用,使用 jmap 把进程内存使用情况 dump 到文件中,再用 jhat 进行分析查看。
  • jstat:JVM 统计监测工具。

可视化工具

  • jconsole:用于对 JVM 的内存、线程、类进行监控,是一个基于 JMX 的 GUI 性能监控工具。
  • jsisualvm:能够监控 CPU、内存使用情况,也可以查看程序运行时候的 GC 情况。

以上就是 Java 提供的一些常用的 JVM 调优辅助工具。

jps 命令

jps 命令主要是查看正在运行的 Java 进程信息,用法如下:

powershell 复制代码
jps

执行结果如下:

powershell 复制代码
14192 nacos-server.jar
27680 RemoteMavenServer36
18852
19508 Launcher
31108 Jps
12232
18280 RemoteMavenServer36
30332 Launcher
powershell 复制代码
jps -l

执行结果如下:

powershell 复制代码
14192 D:\meto\study\nacos\nacos-server-2.3.2\nacos\target\nacos-server.jar
27680 org.jetbrains.idea.maven.server.RemoteMavenServer36
18852
19508 org.jetbrains.jps.cmdline.Launcher
20020 sun.tools.jps.Jps
12232
18280 org.jetbrains.idea.maven.server.RemoteMavenServer36
30332 org.jetbrains.jps.cmdline.Launcher

对比 jps 和 jps -l 命令的区别就是 jps -l 可以看到完整的包路径,而 JPS 命令看不到,两个命令都可以看到进程号。

jinfo 命令

jinfo 命令需要用于实时查看正在运行的 Java 进程基本信息,包括启动参数、垃圾回收器等信息。

jinfo 命令的执行方式是:jinfo pid,执行如下:

powershell 复制代码
jinfo 14192

执行结果如下:

powershell 复制代码
Attaching to process ID 14192, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
Java System Properties:

java.vendor = Oracle Corporation
sun.java.launcher = SUN_STANDARD
catalina.base = D:\meto\study\nacos\nacos-server-2.3.2\nacos\bin
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
catalina.useNaming = false
nacos.local.ip = 192.168.123.132
loader.path = D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins,D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins/health,D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins/cmdb,D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins/selector
os.name = Windows 10
sun.boot.class.path = D:\tool\jdk\jdk\jre\lib\resources.jar;D:\tool\jdk\jdk\jre\lib\rt.jar;D:\tool\jdk\jdk\jre\lib\sunrsasign.jar;D:\tool\jdk\jdk\jre\lib\jsse.jar;D:\tool\jdk\jdk\jre\lib\jce.jar;D:\tool\jdk\jdk\jre\lib\charsets.jar;D:\tool\jdk\jdk\jre\lib\jfr.jar;D:\tool\jdk\jdk\jre\classes
sun.desktop = windows
java.vm.specification.vendor = Oracle Corporation
java.runtime.version = 1.8.0_121-b13
user.name = user.name
user.language = zh
sun.boot.library.path = D:\tool\jdk\jdk\jre\bin
com.zaxxer.hikari.pool_number = 1
CONSOLE_LOG_CHARSET = GBK
nacos.home = D:\meto\study\nacos\nacos-server-2.3.2\nacos
PID = 14192
java.version = 1.8.0_121
user.timezone = Asia/Shanghai
sun.arch.data.model = 64
java.endorsed.dirs = D:\tool\jdk\jdk\jre\lib\endorsed
sun.cpu.isalist = amd64
sun.jnu.encoding = GBK
file.encoding.pkg = sun.io
file.separator = \
java.specification.name = Java Platform API Specification
java.class.version = 52.0
nacos.standalone = true
user.country = CN
java.home = D:\tool\jdk\jdk\jre
java.vm.info = mixed mode
os.version = 10.0
path.separator = ;
java.vm.version = 25.121-b13
user.variant =
java.protocol.handler.pkgs = org.springframework.boot.loader
java.awt.printerjob = sun.awt.windows.WPrinterJob
sun.io.unicode.encoding = UnicodeLittle
awt.toolkit = sun.awt.windows.WToolkit
sun.stdout.encoding = ms936
user.script =
user.home = C:\Users\Administrator
java.specification.vendor = Oracle Corporation
java.library.path = D:\tool\jdk\jdk\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;D:\tool\jdk\jdk\bin;D:\tool\jdk\jdk\jre\bin;D:\tool\git\Git\cmd;D:\tool\svn\bin;D:\tool\maven\apache-maven-3.8.4-bin\apache-maven-3.8.4\bin;D:\tool\web\nodejs\;C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;C:\Users\Administrator\AppData\Roaming\npm;D:\tool\web\webstorm\Microsoft VS Code\bin;D:\tool\idea202103\IntelliJ IDEA 2021.3.3\bin;;.
java.vendor.url = http://java.oracle.com/
spring.beaninfo.ignore = true
java.vm.vendor = Oracle Corporation
java.runtime.name = Java(TM) SE Runtime Environment
sun.java.command = D:\meto\study\nacos\nacos-server-2.3.2\nacos\target\nacos-server.jar --spring.config.additional-location=file:D:\meto\study\nacos\nacos-server-2.3.2\nacos/conf/ --logging.config=D:\meto\study\nacos\nacos-server-2.3.2\nacos/conf/nacos-logback.xml nacos.nacos
java.class.path = D:\meto\study\nacos\nacos-server-2.3.2\nacos\target\nacos-server.jar
nacos.function.mode = All
java.vm.specification.name = Java Virtual Machine Specification
java.vm.specification.version = 1.8
catalina.home = D:\meto\study\nacos\nacos-server-2.3.2\nacos\bin
sun.cpu.endian = little
sun.os.patch.level =
java.awt.headless = true
java.io.tmpdir = C:\Users\ADMINI~1\AppData\Local\Temp\
FILE_LOG_CHARSET = GBK
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
os.arch = amd64
java.awt.graphicsenv = sun.awt.Win32GraphicsEnvironment
java.ext.dirs = D:\tool\jdk\jdk\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
user.dir = D:\meto\study\nacos\nacos-server-2.3.2\nacos\bin
line.separator =

java.vm.name = Java HotSpot(TM) 64-Bit Server VM
nacos.mode = stand alone
sun.stderr.encoding = ms936
file.encoding = GBK
java.specification.version = 1.8

VM Flags:
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=536870912 -XX:MaxHeapSize=536870912 -XX:MaxNewSize=268435456 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=268435456 -XX:OldSize=268435456 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -Xms512m -Xmx512m -Xmn256m -Dnacos.standalone=true -Dloader.path=D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins,D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins/health,D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins/cmdb,D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins/selector -Dnacos.home=D:\meto\study\nacos\nacos-server-2.3.2\nacos

可以看到执行 jinfo 命令打印了非常多的信息,包括 Java 版本、环境信息、JVM 参数等非常多的信息,这些信息并不是我们都要关注的,如果我们想要少看到一些信息,可以使用 jinfo -flags 线程pid 命令。

powershell 复制代码
jinfo -flags 14192

执行结果如下:

powershell 复制代码
Attaching to process ID 14192, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=536870912 -XX:MaxHeapSize=536870912 -XX:MaxNewSize=268435456 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=268435456 -XX:OldSize=268435456 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -Xms512m -Xmx512m -Xmn256m -Dnacos.standalone=true -Dloader.path=D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins,D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins/health,D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins/cmdb,D:\meto\study\nacos\nacos-server-2.3.2\nacos/plugins/selector -Dnacos.home=D:\meto\study\nacos\nacos-server-2.3.2\nacos

可以看到执行 jinfo -flags 命令后打印的信息少了很多,主要都是 JVM 的一些参数信息,这些信息是我们需要重点关注的信息。

jstack 命令

jstack 命令,主要用于查看 Java 进程内线程的堆栈信息,用法如下:

powershell 复制代码
jstack 进程id

进程 id 就是 Java 进行的 id,执行命令如下:

powershell 复制代码
jstack 114684

执行结果如下:

powershell 复制代码
2024-11-20 19:51:55
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.251-b08 mixed mode):

"Keep-Alive-Timer" #13930 daemon prio=8 os_prio=0 tid=0x00007fb22c0de800 nid=0x1834c waiting on condition [0x00007fb1a9b93000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at sun.net.www.http.KeepAliveCache.run(KeepAliveCache.java:172)
        at java.lang.Thread.run(Thread.java:748)

"pool-3-thread-17" #10344 prio=5 os_prio=0 tid=0x00007fb2562f0000 nid=0x1068a waiting on condition [0x00007fb1ad9d1000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000dd9903f0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

"org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#6-2" #10343 prio=5 os_prio=0 tid=0x00007fb1e0de2000 nid=0x1067e waiting on condition [0x00007fb1a928a000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000dd993d78> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
        at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
        at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.nextMessage(BlockingQueueConsumer.java:499)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:927)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:913)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:81)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1284)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1190)
        at java.lang.Thread.run(Thread.java:748)

"pool-3-thread-16" #10342 prio=5 os_prio=0 tid=0x00007fb256f9a800 nid=0x1067b waiting on condition [0x00007fb1a4f53000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000dd9903f0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

"pool-3-thread-15" #10341 prio=5 os_prio=0 tid=0x00007fb256809800 nid=0x1067a waiting on condition [0x00007fb1acfc7000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000dd9903f0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

"pool-3-thread-14" #10340 prio=5 os_prio=0 tid=0x00007fb256542800 nid=0x10679 waiting on condition [0x00007fb1af1e1000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000dd9903f0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

"pool-3-thread-13" #10339 prio=5 os_prio=0 tid=0x00007fb22801b000 nid=0x10677 waiting on condition [0x00007fb1aded6000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000dd9963e8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

"AMQP Connection 10.100.40.29:5672" #10338 prio=5 os_prio=0 tid=0x00007fb22800a000 nid=0x10676 runnable [0x00007fb1adfd7000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:171)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
        - locked <0x00000000dd995db0> (a java.io.BufferedInputStream)
        at java.io.DataInputStream.readUnsignedByte(DataInputStream.java:288)
        at com.rabbitmq.client.impl.Frame.readFrom(Frame.java:91)
        at com.rabbitmq.client.impl.SocketFrameHandler.readFrame(SocketFrameHandler.java:184)
        - locked <0x00000000dd995d90> (a java.io.DataInputStream)
        at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:598)
        at java.lang.Thread.run(Thread.java:748)

"org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#4-2" #10334 prio=5 os_prio=0 tid=0x00007fb1dc02d800 nid=0x10671 waiting on condition [0x00007fb1ae0d8000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000dd991b78> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
        at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
        at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.nextMessage(BlockingQueueConsumer.java:499)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:927)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:913)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:81)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1284)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1190)
        at java.lang.Thread.run(Thread.java:748)

"org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#2-2" #10331 prio=5 os_prio=0 tid=0x00007fb1c8030800 nid=0x1066f waiting on condition [0x00007fb1adad2000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000dd992c88> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
        at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
        at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.nextMessage(BlockingQueueConsumer.java:499)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:927)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:913)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:81)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1284)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1190)
        at java.lang.Thread.run(Thread.java:748)

"org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-2" #10332 prio=5 os_prio=0 tid=0x00007fb1b8031000 nid=0x1066e waiting on condition [0x00007fb1af2e2000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000dd994e98> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
        at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
        at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.nextMessage(BlockingQueueConsumer.java:499)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:927)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:913)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:81)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1284)
        at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1190)
        at java.lang.Thread.run(Thread.java:748)

可以看到执行 jstack 命令后,输出了线程堆栈信息,因为会输出当前进程中的所有线程堆栈信息,会非常多,这里只贴出来了一小部分。

以上就是 jstack 命令的使用方法,jstack 命令主要用于查看 Java 进程对应的线程运行情况。

jmap 命令

jmap 命令非常实用,主要用于生成堆转内存快照,方便查看内存的使用情况,用法如下:

powershell 复制代码
jmap -heap  114684

执行结果如下:

powershell 复制代码
Attaching to process ID 114684, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.251-b08

using thread-local object allocation.
Parallel GC with 4 thread(s)

//堆配置
Heap Configuration:
   //空闲堆空间的最小百分比
   MinHeapFreeRatio         = 0
   //空闲堆空间的最大百分比
   MaxHeapFreeRatio         = 100
   //堆空间允许的最大值
   MaxHeapSize              = 1073741824 (1024.0MB)
   //新生代堆空间的默认值
   NewSize                  = 357564416 (341.0MB)
   //新生代堆空间允许的最大值
   MaxNewSize               = 357564416 (341.0MB)
   //老年代堆空间的默认值
   OldSize                  = 716177408 (683.0MB)
   //新生代与老年代的堆空间比值 新生代:老年代=1:2
   NewRatio                 = 2
   //Eden 区域和 Survivor 区域的比值 8:1:1
   SurvivorRatio            = 8
   //元空间默认值
   MetaspaceSize            = 268435456 (256.0MB)
   //压缩卷使用空间大小
   CompressedClassSpaceSize = 528482304 (504.0MB)
   //元空间允许的最大值
   MaxMetaspaceSize         = 536870912 (512.0MB)
   //使用 G1 垃圾回收器时 每个 Region 空间的大小
   G1HeapRegionSize         = 0 (0.0MB)

//JVM 堆中各个区域内存使用情况
Heap Usage:
PS Young Generation
Eden Space:
   capacity = 352321536 (336.0MB)
   used     = 34211200 (32.6263427734375MB)
   free     = 318110336 (303.3736572265625MB)
   9.710221063523065% used
From Space:
   capacity = 2621440 (2.5MB)
   used     = 1721936 (1.6421661376953125MB)
   free     = 899504 (0.8578338623046875MB)
   65.6866455078125% used
To Space:
   capacity = 2621440 (2.5MB)
   used     = 0 (0.0MB)
   free     = 2621440 (2.5MB)
   0.0% used
PS Old Generation
   capacity = 716177408 (683.0MB)
   used     = 500095856 (476.92857360839844MB)
   free     = 216081552 (206.07142639160156MB)
   69.82848808322086% used

67973 interned Strings occupying 6972816 bytes.

jmap 命令不仅可以直接查看当前堆内存情况的用法,还有一个重要的用途是用来导出 dump 文件。

使用 jmap 导出 dump 文件,用法如下:

powershell 复制代码
jmap -dump:format=b,file=heap.hprof <pid>
  • format=b:表示以 hprof 二进制格式转储 Java 堆的内存。
  • file=heap.hprof: heap.hprof 是你定义的快照 dump 文件的文件名。
  • :Java 进程 id。
powershell 复制代码
jmap -dump:format=b,file=heap.hprof <pid>

演示案例如下:

powershell 复制代码
jmap -dump:format=b,file=/tmp/mydump.hprof 114684

执行结果如下:

powershell 复制代码
Dumping heap to /tmp/mydump.hprof ...
Heap dump file created

去 tmp 目录下查询文件结果如下:

jmap 命令生成的 dump 文件是一个进程或系统在某一给定时间的快照,比如在进程崩溃时,我们可以通过 jmap 命令生成 dump 文件方便进行问题排查,dump 文件中包含了程序运行的线程信息、堆栈调用信息、异常信息等。

jhat 命令

jhat 命令的作用就是分析 jmap 转储的 dump 文件。

使用演示如下:

powershell 复制代码
jhat mydump.hprof 

命令执行结果如下:

powershell 复制代码
Reading from mydump.hprof...
Dump file created Wed Nov 20 17:25:56 CST 2024
Snapshot read, resolving...
Resolving 8852631 objects...
Chasing references, expect 1770 dots..........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Eliminating duplicate references..........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

命令执行完成后,我们看到了这么一句话:Started HTTP server on port 7000,也就是在本机服务器的 7000 端口上运行了一个小程序,我们可以通过 7000 端口进行访问,其实在执行 jhat 命令后,会启动一个内置的 HTTP 服务器,分析 dump 文件并将结果以HTML形式展示。

我们在浏览器访问如下:

jhat 命令的分享就到这里啦。

jstat 命令

jstat 是 JDK 自带的一个轻量级 JVM 调优工具,全称 "Java Virtual Machine statistics monitoring tool",主要利用 JVM 内建的指令对 Java 应用程序的资源和性能进行实时的命令行的监控,包括了对 JVM 堆的各个空间的监控以及垃回收的相关信息统计,常用命令如下(pid 是 Java 应用进程id):

  • jstat -class pid:查看 Java 进程加载的 class 数量,以及所占空间信息。
  • jstat -compiler pid: 查看 Java 进程 JVM 实时编译信息。
  • jstat -gc pid:查看 Java 进程的 gc 相关信息。
  • jstat -gccapacity pid:查看 Java 进程内存中堆内存的大小分布。
  • jstat -gccause pid:查看 Java 进程有关垃圾收集的信息。
  • jstat -gcnew pid:查看 Java 进程中 JVM 年轻代的对象信息。
  • jstat -gcnewcapacity pid:查看 Java 进程中 JVM 年轻代的空间大小。
  • jstat -gcold pid:查看 Java 进程中 JVM 老年代的空间大小。
  • jstat -gcoldcapacity pid:查看 Java 进程中 JVM 老年代容量大小统计。
  • jstat -gcmetacapacity pid:查看 Java 进程中 JVM 元空间信息统计。
  • jstat -gcutil pid:查看 Java 进程中 JVM 垃圾收集信息统计。
  • jstat -printcompilation pid:查看 JVM 编译方法的统计。

jstat -class pid 命令演示:

powershell 复制代码
jstat -class 114368

执行结果如下:

powershell 复制代码
Loaded  Bytes  Unloaded  Bytes     Time   
 28132 51810.5        0     0.0      41.06

结果分析:

  • Loaded:装载的类的数量,这里是 28132 个类。
  • Bytes:装载的字节数,这里是 51810.5 字节。
  • Unloaded:卸载的类的数量,没有被卸载的类。
  • Bytes:卸载的类字节数,卸载的类的字节数。
  • Time:装载和卸载类使用的时间,这里是 41.06秒。

jstat -compiler pid 命令演示:

powershell 复制代码
jstat -compiler 114368

执行结果如下:

powershell 复制代码
Compiled Failed Invalid   Time   FailedType FailedMethod
   35011      1       0   133.75          1 com/alibaba/csp/sentinel/util/TimeUtil$1 run

结果分析:

  • Compiled:编译执行的任务数量,这里是 35011 个。
  • Failed:编译失败的任务数量,这里是 1个。
  • Invalid:编译任务执行失效的数量,这里 0个。
  • Time:编译任务消耗的时间,这里是 133.75秒。
  • FailedMethod:最后一个编译失败任务所在的类及方法。

jstat -gc pid 命令演示:

powershell 复制代码
jstat -gc 114368

执行结果如下:

powershell 复制代码
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
1536.0 1536.0  0.0   368.0  346112.0 214732.0  699392.0   597598.7  169856.0 159867.7 20864.0 19147.1    297    4.072   0      0.000    4.072

结果分析:

  • S0C:Survivor From 区空间容量,单位 KB。
  • S1C:Survivor To 区空间容量,单位 KB。
  • S0U:Survivor From 区空间已经使用的容量,单位 KB。
  • S1U:Survivor To 区空间已经使用的容量,单位 KB。
  • EC:Eden 区域空间总容量,单位 KB。
  • EU:Eden 区域空间已使用总容量,单位 KB。
  • OC:Old 区域空间总容量,单位 KB。
  • OU:Old 区域空间已经使用的容量,单位 KB。
  • MC:元空间 Metaspace 空间总容量,单位 KB。
  • MU:元空间 Metaspace 空间已经使用的容量,单位 KB。
  • CCSC:压缩类空间容量,单位 KB。
  • CCSU:压缩类空间已经使用的容量,单位 KB。
  • YGC:Minor GC 回收的空间数量,单位 KB。
  • YGCT:Minor GC 回收消耗的时间,单位 秒。
  • FGC:Full GC 回收的空间数量,单位 KB。
  • FGCT:Full GC 回收消耗的时间,单位 秒。
  • GCT:总 GC 时间,单位 秒。

jstat -gcutil pid 命令演示:

powershell 复制代码
jstat -gcutil pid

举例如下:

powershell 复制代码
jstat -gcutil 114368

执行结果如下:

powershell 复制代码
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
 16.50   0.00  43.55  85.35  94.11  91.77    282    3.898     0    0.000    3.898

jstat -gcutil 命令执行结果解释如下:

  • S0:年轻代中第一个 survivor(From) 区已使用内存占当前容量百分比。
  • S1:年轻代中第二个 survivor(To)区已使用内存占当前容量百分比。
  • E:年轻代中 Eden 区已使用的内存占当前容量百分比。
  • O:老年代已使用的内存占当前容量百分比。
  • M:元数据区已使用的占当前容量百分比。
  • CCS:压缩类空间已使用的占当前容量百分比。
  • YGC :从应用程序启动到采样时年轻代中 GC 次数。
  • YGCT :从应用程序启动到采样时年轻代中 GC 所用时间,单位:秒。
  • FGC :从应用程序启动到采样时 Full GC 的次数。
  • FGCT :从应用程序启动到采样时 Full GC所用时间,单位:秒。
  • GCT:从应用程序启动到采样时 GC 用的总时间,单位:秒。

jstat 命令的使用就分享到这里,还有几个跟 GC 相关的用法大同小异,感兴趣的自己去试一下,各个字段的含义也都差不多,只是从不通过粒度上来进行了分析。

总结:本篇分享 JDK 自带的一些 JVM 调优工具的使用,使用 jps、jinfo、jmap、jstack、jhat、jstat 命令来查看 Java 应用程序的堆栈信息,来辅助我们进行 JVM 调优,关于可视化工具的部分我们下一篇再来分享,希望可以帮助到有需要的朋友们。

相关推荐
Ruannn(努力版)1 小时前
Android习题第五章数据存储
android·jvm
蚰蜒螟2 小时前
openjdk17 jvm 对象 内存溢出 在C++源码体现
开发语言·jvm·c++
小小工匠3 小时前
Java - JSR223规范解读_在JVM上实现多语言支持
java·jvm·jsr223
蚰蜒螟3 小时前
openjdk17 jvm 大对象 内存分配 在C++源码体现
java·jvm·c++
熙曦Sakura3 小时前
APP聊天项目介绍
java·jvm·oracle
王佑辉7 小时前
【jvm】C2编译器
jvm
我不是大号7 小时前
JVM的垃圾回收算法有哪些
jvm·算法
IsToRestart16 小时前
String的设计,用到了哪些设计模式?
java·jvm·设计模式
喜欢猪猪17 小时前
实战优化公司线上系统JVM:从基础到高级
jvm