linux 排查java cpu过高问题,JPS、JMAP、JSTAT、JSTACK和JCMD

代码: 

[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应用程序进行诊断、监控和管理,从而提高应用程序的可靠性和性能。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值