前言:
前面我们分析怎么去预估系统资源,怎么去设置 JVM 参数以及怎么去看 GC 日志,本篇我们分享一些常用的 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 进程信息,用法如下:
jps
执行结果如下:
14192 nacos-server.jar
27680 RemoteMavenServer36
18852
19508 Launcher
31108 Jps
12232
18280 RemoteMavenServer36
30332 Launcher
jps -l
执行结果如下:
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,执行如下:
jinfo 14192
执行结果如下:
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 命令。
jinfo -flags 14192
执行结果如下:
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 进程内线程的堆栈信息,用法如下:
jstack 进程id
进程 id 就是 Java 进行的 id,执行命令如下:
jstack 114684
执行结果如下:
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 命令非常实用,主要用于生成堆转内存快照,方便查看内存的使用情况,用法如下:
jmap -heap 114684
执行结果如下:
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 文件,用法如下:
jmap -dump:format=b,file=heap.hprof <pid>
- format=b:表示以 hprof 二进制格式转储 Java 堆的内存。
- file=heap.hprof: heap.hprof 是你定义的快照 dump 文件的文件名。
- :Java 进程 id。
jmap -dump:format=b,file=heap.hprof <pid>
演示案例如下:
jmap -dump:format=b,file=/tmp/mydump.hprof 114684
执行结果如下:
Dumping heap to /tmp/mydump.hprof ...
Heap dump file created
去 tmp 目录下查询文件结果如下:
jmap 命令生成的 dump 文件是一个进程或系统在某一给定时间的快照,比如在进程崩溃时,我们可以通过 jmap 命令生成 dump 文件方便进行问题排查,dump 文件中包含了程序运行的线程信息、堆栈调用信息、异常信息等。
jhat 命令
jhat 命令的作用就是分析 jmap 转储的 dump 文件。
使用演示如下:
jhat mydump.hprof
命令执行结果如下:
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 命令演示:
jstat -class 114368
执行结果如下:
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 命令演示:
jstat -compiler 114368
执行结果如下:
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 命令演示:
jstat -gc 114368
执行结果如下:
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 命令演示:
jstat -gcutil pid
举例如下:
jstat -gcutil 114368
执行结果如下:
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 调优,关于可视化工具的部分我们下一篇再来分享,希望可以帮助到有需要的朋友们。