JDK基础故障处理工具

基础故障处理工具

  1. Jps:显示指定系统内所有虚拟机进程
  2. jstat:用于收集虚拟机各方面的运行数据
  3. jinfo:显示虚拟机配置信息
  4. jmap:生成虚拟机内存转储存快照
  5. jhat:用于分析heapdump文件
  6. jstack:显示虚拟机的线程快照

1.JPS(运行的进程状态信息)

​ 类似 ps 命令;列出正在运行的虚拟机进程,并显示虚拟机的执行主类(main函数)的名称以及这些进程的本地虚拟机唯一ID(就是PID)

这个命令非常常用,其他 JDK 工具需要依赖 jps 命令来确定要监控的虚拟机进程的 PID

#jps 命令:主要用来输出JVM中运行的进程状态信息
jps [options]
#参数:(常用 -m -l)
-q 只输出pid
-m 输出传入main方法的参数
-l 输出main类或Jar的全限名
-v 输出传入JVM的参数

#例子,第一个数字是当前进程的pid (常用就是 -m -l)
jps -mvl

15329 sun.tools.jps.Jps -mvl -Dapplication.home=/usr/local/jdk1.8 -Xms8m
1466 eureka-dh-1.0.jar -Xms64m -Xmx64m
1612 demo-1.jar -Xms64m -Xmx64m

2.jstat(运行状态信息)

可以显示虚拟机进程中的 类装载、内存、垃圾回收和编译 等数据

jstat [参数] PID [可选参数] 
# 可选参数包含: interval[s|ms]  count  
#    即查询间隔时间和次数; 如果省略可选参数,那么说明只查询一次

#示例:
jstat -gc 1314 250 20
#命令描述:每250毫秒查询一次进程1314的垃圾收集情况, 一共查询20次

jstat参数

选项作用
-class监视类装载、卸载数量、总空间以及类装载所耗费的时间
-gc监视堆状况:包含容量,已用空间和GC时间等信息
-gcnew监视新生代的GC状况
-gcold监视老年代的GC状况
-gcmetacapacity监视元空间的GC状况
-gcutil监视内容和-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-compiler输出编译器编译过的方法、耗时等信息
-gcnewcapacity输出和-gcnew基本相同,主要关注使用到的最大、最小空间
-gcoldcapacity输出和-gcold基本相同,主要关注使用到的最大、最小空间

可选参数

可选参数包括: interval[s|ms] count

即:即 查询间隔时间查询次数 ;如果省略可选参数,那么说明只查询一次

例如:

jstat -gc 1314 250 20
命令描述:每 250 毫秒查询一次进程PID为 1314 的垃圾收集情况, 一共查询20次

1.-class类加载统计

  • **Loaded:**加载class的数量
  • **Bytes:**所占用空间大小
  • **Unloaded:**未加载数量
  • **Bytes:**未加载占用空间
  • **Time:**时间
[root@daiadrian ~]# jstat -class 29359
Loaded  Bytes  Unloaded  Bytes     Time   
   556  1087.5        0     0.0     0.12

2.-gc堆内存统计

  • **S0C:**第一个 Survivor 区的大小
  • **S1C:**第二个 Survivor 区的大小
  • **S0U:**第一个 Survivor 区的使用大小
  • **S1U:**第二个 Survivor 区的使用大小
  • **EC:**Eden区的大小
  • **EU:**Eden区的使用大小
  • **OC:**老年代大小
  • **OU:**老年代使用大小
  • **MC:**方法区大小
  • **MU:**方法区使用大小
  • **CCSC:**压缩类空间大小
  • **CCSU:**压缩类空间使用大小
  • **YGC:**年轻代垃圾回收次数
  • **YGCT:**年轻代垃圾回收消耗时间
  • **FGC:**老年代垃圾回收次数
  • **FGCT:**老年代垃圾回收消耗时间
  • **GCT:**垃圾回收消耗总时间
[root@daiadrian ~]# jstat -gc 29359
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
1024.0 1024.0  0.0    0.0    8192.0   2474.5   20480.0      0.0     4480.0 774.4  384.0   75.9       0    0.000   0      0.000    0.000

3.-gcnew新生代垃圾回收统计

  • **S0C:**第一个 Survivor 区大小
  • **S1C:**第二个 Survivor 区的大小
  • **S0U:**第一个 Survivor 区的使用大小
  • **S1U:**第二个 Survivor 区的使用大小
  • **TT:**对象在新生代存活的次数
  • **MTT:**对象在新生代存活的最大次数
  • **DSS:**期望的幸存区大小
  • **EC:**Eden区的大小
  • **EU:**Eden区的使用大小
  • **YGC:**年轻代垃圾回收次数
  • **YGCT:**年轻代垃圾回收消耗时间
[root@daiadrian ~]# jstat -gcnew 29359
 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT  
1024.0 1024.0    0.0    0.0 15  15    0.0   8192.0   2474.5      0    0.000

4.-gcold老年代垃圾回收统计

  • **MC:**方法区大小
  • **MU:**方法区使用大小
  • **CCSC:**压缩类空间大小
  • **CCSU:**压缩类空间使用大小
  • **OC:**老年代大小
  • **OU:**老年代使用大小
  • **YGC:**年轻代垃圾回收次数
  • **FGC:**老年代垃圾回收次数
  • **FGCT:**老年代垃圾回收消耗时间
  • **GCT:**垃圾回收消耗总时间
[root@daiadrian ~]# jstat -gcold 29359
   MC       MU      CCSC     CCSU       OC          OU       YGC    FGC    FGCT     GCT   
  4480.0    774.4    384.0     75.9     20480.0     0.0      0       0    0.000    0.000

5.-gcmetacapacity元数据空间统计

  • MCMN: 最小元数据容量
  • **MCMX:**最大元数据容量
  • **MC:**当前元数据空间大小
  • **CCSMN:**最小压缩类空间大小
  • **CCSMX:**最大压缩类空间大小
  • **CCSC:**当前压缩类空间大小
  • **YGC:**年轻代垃圾回收次数
  • **FGC:**老年代垃圾回收次数
  • **FGCT:**老年代垃圾回收消耗时间
  • **GCT:**垃圾回收消耗总时间
[root@daiadrian ~]# jstat -gcmetacapacity 29359
   MCMN    MCMX        MC       CCSMN      CCSMX       CCSC     YGC   FGC    FGCT     GCT    0.0  1056768.0     4480.0        0.0  1048576.0    384.0     0     0    0.000  0.000

6.-gcutil

  • **S0:**Survivor 1区当前使用比例
  • **S1:**Survivor 2区当前使用比例
  • **E:**Eden区使用比例
  • **O:**老年代使用比例
  • **M:**元数据区使用比例
  • **CCS:**压缩使用比例
  • **YGC:**年轻代垃圾回收次数
  • **FGC:**老年代垃圾回收次数
  • **FGCT:**老年代垃圾回收消耗时间
  • **GCT:**垃圾回收消耗总时间
[root@daiadrian ~]# jstat -gcutil 1466
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
  0.00   0.05  65.76  64.32  95.33  93.82    394    1.614     3    0.227    1.840

3.jmap(生成堆转存储快照)

​ jmap 命令用于生成堆转存储快照(一般为 dump 或 heapdump 文件),生成的快照是**当前时刻** 的内存快照

​ 除了 jmap 命令,也可以启动 java 程序时指定参数 -XX:+HeapDumpOutOfMemoryError ,可以让虚拟机在发生OOM异常的时候自动生成 dump 文件

​ jmap 命令除了能够获取到堆转存储快照,还能查询 finalize 执行队列,Java 堆和永久代的详细信息(如空间使用率,当前使用哪种垃圾收集器等)

jmap [option] vmid
# option是参数
# vmid是通过 jps 命令查询出来的 ID

jmap参数

选项作用
-dump生成堆转存储快照
-heap显示堆的详细信息,如使用哪种垃圾收集器、参数配置、分代状况
-histo显示堆中对象统计信息,包括类、实例数量、合计容量
-permstat以ClassLoader为统计口径显示永久代内存状态
-F当虚拟机对-dump选项不起作用时,可以使用该命令强制生成dump文件
-finalizerinfo显示在F-Queue中等待Finalizer线程执行finalize方法的对象

4.jstack(堆栈跟踪工具)重要

​ jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照(一般称为 threaddump 或者 javacore 文件)

​ 线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的目的通常是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等,都是导致线程长时间停顿的常见原因

​ 线程出现停顿时通过 jstack 命令来查看各个线程的调用堆栈,就可以获知没有响应的线程到底在后台做些什么事情,或者等待着什么资源

#命令格式, vmid 即 jps 命令查出来的pid
jstack [option] vmid

参数选项:

选项详解
-F当正常输出的请求不被响应时,强制输出线程堆栈
-l除堆栈外,显示关于锁的附加信息(发生死锁时,可以观察锁持有情况)
-m如果调用到本地方法(Native方法)的话,可以显示C/C++的堆栈

线程死锁示例

public class Test {

    public static void main(String[] args) {
        String A = new String("A");
        String B = new String("B");

        new Thread(() -> {
            synchronized (A) {
                System.out.println("AAA::");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (B) {
                    System.out.println("A---B");
                }
            }
        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (B) {
                System.out.println("BBB::");
                synchronized (A) {
                    System.out.println("B---A");
                }
            }
        }).start();

    }

}
[root@daiadrian ~]# jps -mvl
15601 sun.tools.jps.Jps -mvl -Dapplication.home=/usr/local/jdk1.8 -Xms8m
15570 Test
[root@daiadrian ~]# jstack -l 15570

输出内容:

2020-08-16 11:34:12
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode):

"Attach Listener" #11 daemon prio=9 os_prio=0 tid=0x00007f1f68001000 nid=0x3d05 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"DestroyJavaVM" #10 prio=5 os_prio=0 tid=0x00007f1f90008800 nid=0x3cd3 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"Thread-1" #9 prio=5 os_prio=0 tid=0x00007f1f900f4800 nid=0x3cdd waiting for monitor entry [0x00007f1f80ffe000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at Test.lambda$main$1(Test.java:30)
	- waiting to lock <0x00000000e345bed0> (a java.lang.String)
	- locked <0x00000000e345bf18> (a java.lang.String)
	at Test$$Lambda$2/471910020.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
	- None

"Thread-0" #8 prio=5 os_prio=0 tid=0x00007f1f900f2800 nid=0x3cdc waiting for monitor entry [0x00007f1f941b8000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at Test.lambda$main$0(Test.java:16)
	- waiting to lock <0x00000000e345bf18> (a java.lang.String)
	- locked <0x00000000e345bed0> (a java.lang.String)
	at Test$$Lambda$1/791452441.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
	- None

"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007f1f900b3000 nid=0x3cda runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f1f900b0000 nid=0x3cd9 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f1f900ad800 nid=0x3cd8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f1f900ac000 nid=0x3cd7 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f1f90079000 nid=0x3cd6 in Object.wait() [0x00007f1f947be000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x00000000e3408ec8> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
	- locked <0x00000000e3408ec8> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

   Locked ownable synchronizers:
	- None

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f1f90074800 nid=0x3cd5 in Object.wait() [0x00007f1f948bf000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x00000000e3406b68> (a java.lang.ref.Reference$Lock)
	at java.lang.Object.wait(Object.java:502)
	at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
	- locked <0x00000000e3406b68> (a java.lang.ref.Reference$Lock)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

   Locked ownable synchronizers:
	- None

"VM Thread" os_prio=0 tid=0x00007f1f9006d000 nid=0x3cd4 runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007f1f900b6000 nid=0x3cdb waiting on condition 

JNI global references: 308


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f1f74004e28 (object 0x00000000e345bed0, a java.lang.String),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f1f740062c8 (object 0x00000000e345bf18, a java.lang.String),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
	at Test.lambda$main$1(Test.java:30)
	- waiting to lock <0x00000000e345bed0> (a java.lang.String)
	- locked <0x00000000e345bf18> (a java.lang.String)
	at Test$$Lambda$2/471910020.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
"Thread-0":
	at Test.lambda$main$0(Test.java:16)
	- waiting to lock <0x00000000e345bf18> (a java.lang.String)
	- locked <0x00000000e345bed0> (a java.lang.String)
	at Test$$Lambda$1/791452441.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock. # 表示当前有一个死锁的情况
jstack内容解析
"Thread-1" #9 prio=5 os_prio=0 tid=0x00007f1f900f4800 nid=0x3cdd waiting for monitor entry [0x00007f1f80ffe000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at Test.lambda$main$1(Test.java:30)
	- waiting to lock <0x00000000e345bed0> (a java.lang.String)
	- locked <0x00000000e345bf18> (a java.lang.String)
	at Test$$Lambda$2/471910020.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
	- None

"Thread-0" #8 prio=5 os_prio=0 tid=0x00007f1f900f2800 nid=0x3cdc waiting for monitor entry [0x00007f1f941b8000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at Test.lambda$main$0(Test.java:16)
	- waiting to lock <0x00000000e345bf18> (a java.lang.String)
	- locked <0x00000000e345bed0> (a java.lang.String)
	at Test$$Lambda$1/791452441.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
	- None
  1. 这里的这两个线程内容就是代码中的两个线程信息
  2. waiting for monitor entry 表示当前线程正在等待某个 monitor 释放
  3. nid=0x3cdd 表示当前的线程 nid 是多少,这个 nid 线程 PID 的十六进制的值(0x 表示十六进制)
  4. 其中 java.lang.Thread.State 表示当前线程的状态,BLOCKED 表示当前线程是阻塞状态
  5. at Test.lambda$main$1(Test.java:30) 指出了阻塞住的代码是在哪个类的哪一行
  6. - waiting to lock <0x00000000e345bed0> (a java.lang.String) 表示当前的线程在等待哪一个锁对象,这个对象是一个 String 字符串类型
  7. - locked <0x00000000e345bf18> (a java.lang.String) 表示当前线程锁定的对象,是一个字符串类型的对象
Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f1f74004e28 (object 0x00000000e345bed0, a java.lang.String),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f1f740062c8 (object 0x00000000e345bf18, a java.lang.String),
  which is held by "Thread-1"
  1. Found one Java-level deadlock 表示发现了当前有一个死锁
  2. waiting to lock monitor 0x00007f1f74004e28 (object 0x00000000e345bed0, a java.lang.String) 表示当前这个线程正在等待一个 monitor
  3. which is held by "Thread-0" 表示等待的 monitor 被哪个线程持有(heldhold 的过去式)
Java stack information for the threads listed above:
===================================================
"Thread-1":
	at Test.lambda$main$1(Test.java:30)
	- waiting to lock <0x00000000e345bed0> (a java.lang.String)
	- locked <0x00000000e345bf18> (a java.lang.String)
	at Test$$Lambda$2/471910020.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
"Thread-0":
	at Test.lambda$main$0(Test.java:16)
	- waiting to lock <0x00000000e345bf18> (a java.lang.String)
	- locked <0x00000000e345bed0> (a java.lang.String)
	at Test$$Lambda$1/791452441.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)

这里列出了死锁的详细信息,具体的解析内容查看上面解析

查看应用某个线程的堆栈信息

找出某个 Java 进程中最耗费CPU的 Java 线程并定位堆栈信息

这里的 获取线程的十六进制的值 就是上面示例的 nid 的值

#第一步:先找出Java进程ID
ps -ef | grep Test | grep -v grep
## 输出:root 11415 27727  0 14:53 pts/0  00:00:04 java Test

#第二步找出该进程内最耗费CPU的线程(此处pid是上一步输出的pid)
top -Hp pid

#从第二步找到耗费CPU最多的线程pid
##获取到十六进制值,此处的pid是top中耗费CPU最高的线程pid
printf "%x\n" pid
###假设这里得到 3df0 , 这个就是 nid

#输出进程的堆栈信息,然后根据线程ID的十六进制值grep
jstack pid | grep 3df0 -A 10
##这里结果能得到哪个类中的哪一行代码耗费CPU较高

相关内容查看上面解析

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值