代码:
[root@localhost cpu]# cat Test.java
public class Test {
public static void main(String[] args) {
new Thread(()->{
System.out.println("11111");
while(true) {
}
},"thread1").start();
new Thread(()->{
System.out.println("2222");
try {
Thread.sleep(100000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},"thread2").start();
new Thread(()->{
System.out.println("33333");
try {
Thread.sleep(100000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},"thread2").start();
}
}
编译:
[root@localhost cpu]# javac Test.java
运行 :
[root@localhost cpu]# java Test
11111
2222
3333
1.查看cpu过高的进程
[root@localhost ~]# top -c
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
13607 root 20 0 6817792 25132 11464 S 100.0 0.2 0:18.35 java Test
13638 root 20 0 162292 2508 1680 R 1.0 0.0 0:00.04 top -c
16159 root 20 0 7939008 4.6g 11944 S 1.0 29.4 3096:16 java -Duser.home=/v
2.查看13607进程的线程有哪些且哪些占用高
进程号:13607为列子
[root@localhost work]# ps H -eo pid,tid,%cpu |grep 13607
13607 13607 0.0
13607 13608 0.2
13607 13610 0.0
13607 13611 0.0
13607 13612 0.0
13607 13613 0.0
13607 13614 0.0
13607 13615 0.0
13607 13616 0.0
13607 13617 0.0
13607 13618 0.0
13607 13619 0.0
13607 13620 0.0
13607 13621 0.0
13607 13622 0.0
13607 13623 98.8
13607 13624 0.0
13607 13625 0.0
3.从这我们可以看到tid 13623 这个线程占用很高,达到了98.8但具体是程序的那一个线程造成的呢?我们可以使用jstack pid,它会输出相关堆栈信息。 jstack 进程id,注意不是线程
[root@localhost work]# jstack 13607
2023-07-26 15:34:44
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.321-b07 mixed mode):
"Attach Listener" #13 daemon prio=9 os_prio=0 tid=0x00007fca34001000 nid=0x35cb waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"DestroyJavaVM" #12 prio=5 os_prio=0 tid=0x00007fca78009800 nid=0x3528 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"thread1" #9 prio=5 os_prio=0 tid=0x00007fca781a1800 nid=0x3537 runnable [0x00007fca636f5000]
java.lang.Thread.State: RUNNABLE
at Test.lambda$main$0(Test.java:5)
at Test$$Lambda$1/471910020.run(Unknown Source)
at java.lang.Thread.run(Thread.java:750)
"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x00007fca780f3000 nid=0x3535 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007fca780c0000 nid=0x3534 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007fca780be000 nid=0x3533 waiting on c
jstack 进程pid之后输出的线程信息是16进制的,我们将tid 13623 用计算器转为16进制可以看到是 3537
线程:13623 转好为16进制
[root@localhost work]# printf "%x\n" 13623
3537
4. 查看代码哪里出现出问题 看前20行
[root@localhost ~]# jstack 进程号(pid)|grep 线程tid16进制 -A20
[root@localhost ~]# jstack 13607 |grep 3537 -A20
[root@localhost work]# jstack 13607 |grep 3537 -A20
"thread1" #9 prio=5 os_prio=0 tid=0x00007fca781a1800 nid=0x3537 runnable [0x00007fca636f5000]
java.lang.Thread.State: RUNNABLE
at Test.lambda$main$0(Test.java:5)
at Test$$Lambda$1/471910020.run(Unknown Source)
at java.lang.Thread.run(Thread.java:750)
"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x00007fca780f3000 nid=0x3535 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007fca780c0000 nid=0x3534 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007fca780be000 nid=0x3533 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007fca780bb000 nid=0x3532 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007fca780b9800 nid=0x3531 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
https://github.com/oldratlee/useful-scripts/blob/dev-2.x/docs/java.md
JMAP、JSTAT和JSTACK是Java开发中常用的工具,用于分析和调试Java应用程序。它们的使用场景如下:
JMAP:JMAP用于生成Java堆转储快照,以便分析Java应用程序的内存使用情况。它可以提供关于对象数量、类型、大小等信息,帮助识别内存泄漏或者内存溢出问题。
JSTAT:JSTAT用于监视和收集Java虚拟机(JVM)的各种统计数据,例如垃圾回收情况、类加载情况、线程数量等。它可以实时显示这些统计数据,帮助开发人员了解应用程序的性能状况。
JSTACK:JSTACK用于生成Java线程转储快照,以便分析Java应用程序的线程状态和调用栈信息。它可以帮助开发人员定位死锁、死循环、线程阻塞等问题,并提供线程运行轨迹,有助于进行线程级别的故障排查。
JCMD是一个多功能的工具,它是一个运用更为全面的工具,可用于获取目标 Java 进程的性能统计、内存使用、垃圾收集、线程堆栈、JVM 运行时间,GC、导出线程信息、堆信息等、简单理解为它可以直接使用相关的名称获取信息
JMAP是一个命令行工具,用于生成Java堆转储快照。
常用选项(属性):
heap: 生成Java堆转储快照。示例:jmap -heap <pid>
histo: 生成Java堆中对象的统计信息,包括对象数量、类型和大小等。示例:jmap -histo <pid>
dump: 生成Java堆转储快照,并保存到文件中。示例:jmap -dump:format=b,file=<filename> <pid>
finalizerinfo: 显示等待终结的对象信息。示例:jmap -finalizerinfo <pid>
clstats: 显示类加载器的统计信息。示例:jmap -clstats <pid>
permstat: 显示永久代(PermGen/Metaspace)的统计信息。示例:jmap -permstat <pid>
[root@localhost work]# jmap -heap 14937
Attaching to process ID 14937, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.321-b07
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 4164943872 (3972.0MB)
NewSize = 87031808 (83.0MB)
MaxNewSize = 1388314624 (1324.0MB)
OldSize = 175112192 (167.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
参数说明:
Heap Configuration: #堆配置情况
MinHeapFreeRatio #堆最小使用比例
MaxHeapFreeRatio #堆最大使用比例
MaxHeapSize #堆最大空间
NewSize #新生代初始化大小
MaxNewSize #新生代可使用最大容量大小
OldSize #老生代大小
NewRatio #新生代比例
SurvivorRatio #新生代与suvivor的占比
MetaspaceSize #元数据空间初始大小
CompressedClassSpaceSize #类指针压缩空间大小, 默认为1G
MaxMetaspaceSize #元数据空间的最大值, 超过此值就会触发 GC溢出( JVM会动态地改变此值)
G1HeapRegionSize #区块的大小
JSTAT的使用
STAT是一个用于监视和收集Java虚拟机(JVM)统计数据的命令行工具。它提供了多个选项和属性,用于显示不同方面的JVM统计信息。
以下是JSTAT的使用方法和常用属性的解析:
使用方法:
输入jstat -<option> <pid> [<interval> [<count>]]
其中<option>为JSTAT的选项,<pid>为Java进程的进程ID,
<interval>为采样间隔时间(以毫秒为单位),<count>为采样次数。
常用选项(属性):
-class:显示类加载、卸载数量和总空间等信息。
-compiler:显示JIT编译器的编译任务和耗时等信息。
-gc:显示垃圾回收器的统计信息,包括堆内存使用、GC时间、吞吐量等。
-gcutil:显示垃圾回收器的详细统计信息,包括堆内存使用、GC时间、吞吐量、GC持续时间等。
-gccause 显示GC触发的原因的时间等
-gccapacity:显示堆内存容量和使用情况的详细信息。
-gcnew:显示新生代垃圾回收器的统计信息。
-gcnewcapacity:显示新生代堆内存容量和使用情况的详细信息。
-gcold:显示老年代垃圾回收器的统计信息。
-gcoldcapacity:显示老年代堆内存容量和使用情况的详细信息。
-gcpermcapacity:显示永久代(PermGen/Metaspace)容量和使用情况的详细信息。
- 每秒中打印一次,打印15次
root@localhost work]# jstat -gccause 14937 1000 15
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
通过查看 新生代、老年代以及GC的次数、时间、调整服务启动参数的设置
参数解析:
S0: 幸存者区(Survivor)0的使用百分比。
S1: 幸存者区(Survivor)1的使用百分比。
E: 伊甸园(Eden)区的使用百分比。
O: 老年代(Old Generation)的使用百分比。
M: 元空间(Metaspace)的使用百分比。
CCS: 压缩类空间(Compressed Class Space)的使用百分比。
YGC: 年轻代垃圾回收的次数。
YGCT: 年轻代垃圾回收的总时间(以秒为单位)。
FGC: Full GC(全局垃圾回收)的次数。
FGCT: Full GC(全局垃圾回收)的总时间(以秒为单位)。
GCT: 所有垃圾回收的总时间(以秒为单位)。
NGCMN: 年轻代最小容量(以KB为单位)。
NGCMX: 年轻代最大容量(以KB为单位)。
NGC: 年轻代当前容量(以KB为单位)。
OGCMN: 老年代最小容量(以KB为单位)。
OGCMX: 老年代最大容量(以KB为单位)。
OGC: 老年代当前容量(以KB为单位)。
MCMN: 元空间最小容量(以KB为单位)。
MCMX: 元空间最大容量(以KB为单位)。
MC: 元空间当前容量(以KB为单位)。
CCSMN: 压缩类空间最小容量(以KB为单位)。
CCSMX: 压缩类空间最大容量(以KB为单位)。
CCSC: 压缩类空间当前容量(以KB为单位)。
通过分析这些参数信息,可以了解垃圾回收器的使用情况、堆内存的使用情况和变化趋势等,帮助识别内存问题并进行性能调优。
-- 查看GC的原因
[root@localhost work]# jstat -gccause 14937 1000 15
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
0.00 0.00 18.00 0.00 17.47 19.94 0 0.000 0 0.000 0.000 No GC No GC
JSTACK的使用
jstack是一个用于生成Java线程转储快照的命令行工具,它可以帮助分析和诊断Java应用程序中的线程问题。
使用方法:
输入jstack [-m] <pid>,其中<pid>为Java进程的进程ID。
常用选项(属性):
-l:输出长格式线程转储,包括锁信息。
-F:当目标Java进程无响应时,强制生成线程转储。
-m:输出Java和本地堆栈信息。
-h:显示帮助信息。
输出解析:
jstack输出的内容包含了当前Java进程中所有线程的堆栈跟踪信息。每个线程的堆栈跟踪以线程ID开始,并按照调用层次结构显示方法调用序列。
以下是一些常见的线程状态和属性的解析:
java.lang.Thread.State:线程的状态,如RUNNABLE(运行中)、WAITING(等待中)、TIMED_WAITING(定时等待中)等。
at <class>.<method>(<file>:<line>):方法调用的堆栈跟踪信息,包括类名、方法名和源代码文件位置。
Locked <monitor>:线程正在持有某个监视器锁。
Waiting on <monitor>:线程正在等待某个监视器锁。
Blocked on <monitor>:线程被阻塞在某个监视器锁上。
通过分析线程转储快照,可以了解Java应用程序中各个线程的状态、堆栈跟踪信息以及可能存在的死锁或性能问题。这对于诊断和解决线程相关的问题非常有帮助。
请注意,jstack命令需要与目标Java进程具有相同的用户权限才能执行成功。另外,建议在生产环境中谨慎使用该命令,以避免对应用程序性能产生不利影响。
root@localhost work]# jstack -l 14937
2023-07-26 16:04:09
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.321-b07 mixed mode):
"Attach Listener" #13 daemon prio=9 os_prio=0 tid=0x00007f67ac001000 nid=0x3cd8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"DestroyJavaVM" #12 prio=5 os_prio=0 tid=0x00007f67f8009800 nid=0x3a5a waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"thread1" #9 prio=5 os_prio=0 tid=0x00007f67f81a2000 nid=0x3a69 runnable [0x00007f67e4627000]
java.lang.Thread.State: RUNNABLE
at Test.lambda$main$0(Test.java:5)
at Test$$Lambda$1/471910020.run(Unknown Source)
at java.lang.Thread.run(Thread.java:750)
Locked ownable synchronizers:
- None
"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x00007f67f80fb000 nid=0x3a66 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C1 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f67f80c0000 nid=0x3a65 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f67f80be000 nid=0x3a64 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
JCMD的使用
使用 jcmd 获取服务进程
[root@localhost work]# jcmd -l
16546 sun.tools.jcmd.JCmd -l
25236 remoting.jar -workDir /opt/work/jenkins/data -jar-cache /opt/work/jenkins/data/remoting/jarCache
14937 Test
使用 jcmd <pid> help 获取可执行命令
[root@localhost work]# jcmd 14937 help
14937:
The following commands are available:
JFR.stop
JFR.start
JFR.dump
JFR.check
VM.native_memory
VM.check_commercial_features
VM.unlock_commercial_features
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
VM.classloader_stats
GC.rotate_log
Thread.print
GC.class_stats
GC.class_histogram
GC.heap_dump
GC.finalizer_info
GC.heap_info
GC.run_finalization
GC.run
VM.uptime
VM.dynlibs
VM.flags
VM.system_properties
VM.command_line
VM.version
help
For more information about a specific command use 'help <command>'.
例如: jcmd 14937 GC.heap_info
[root@localhost work]# jcmd 14937 GC.heap_info
14937:
PSYoungGen total 74752K, used 11613K [0x000000076d400000, 0x0000000772700000, 0x00000007c0000000)
eden space 64512K, 18% used [0x000000076d400000,0x000000076df57440,0x0000000771300000)
from space 10240K, 0% used [0x0000000771d00000,0x0000000771d00000,0x0000000772700000)
to space 10240K, 0% used [0x0000000771300000,0x0000000771300000,0x0000000771d00000)
ParOldGen total 171008K, used 0K [0x00000006c7c00000, 0x00000006d2300000, 0x000000076d400000)
object space 171008K, 0% used [0x00000006c7c00000,0x00000006c7c00000,0x00000006d2300000)
Metaspace used 3396K, capacity 4636K, committed 4864K, reserved 1056768K
class space used 378K, capacity 461K, committed 512K, reserved 1048576K
例如: jcmd 14937 Thread.print
root@localhost work]# jcmd 14937 Thread.print
14937:
2023-07-26 16:05:53
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.321-b07 mixed mode):
"Attach Listener" #13 daemon prio=9 os_prio=0 tid=0x00007f67ac001000 nid=0x3cd8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"DestroyJavaVM" #12 prio=5 os_prio=0 tid=0x00007f67f8009800 nid=0x3a5a waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"thread1" #9 prio=5 os_prio=0 tid=0x00007f67f81a2000 nid=0x3a69 runnable [0x00007f67e4627000]
java.lang.Thread.State: RUNNABLE
at Test.lambda$main$0(Test.java:5)
at Test$$Lambda$1/471910020.run(Unknown Source)
at java.lang.Thread.run(Thread.java:750)
"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x00007f67f80fb000 nid=0x3a66 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f67f80c0000 nid=0x3a65 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f67f80be000 nid=0x3a64 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f67f80bb000 nid=0x3a63 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f67f80b9800 nid=0x3a62 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f67f8086800 nid=0x3a61 in Object.wait() [0x00007f67e4d2e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076d408ee8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x000000076d408ee8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f67f8082000 nid=0x3a60 in Object.wait() [0x00007f67e4e2f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076d406c00> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x000000076d406c00> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=0 tid=0x00007f67f8078000 nid=0x3a5f runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f67f801e800 nid=0x3a5b runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f67f8020800 nid=0x3a5c runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f67f8022800 nid=0x3a5d runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f67f8024000 nid=0x3a5e runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007f67f8100000 nid=0x3a67 waiting on condition
总之,jcmd是一个功能强大的工具,可以帮助开发人员和运维人员对Java应用程序进行诊断、监控和管理,从而提高应用程序的可靠性和性能。