1一乐

V1

2022/01/26阅读:60主题:默认主题

java基础教程虚拟机性能分析和故障解决工具

 


java基础教程虚拟机性能分析和故障解决工具

--------------作用:帮助判断cpu占用率过高、死循环、死锁、内存泄露、内存溢出等等问题。

 

 

需要掌握

jps 查看进程ID

  命令:jps

jstat 实时查看java进程运行的数据情况,可以判断是否内存泄露或者内存溢出的情况

  命令:jstat -gc 进程IDpid号)  或者 jstat -gcutil 进程ID

jstack ,查看或导出 Java 应用程序中线程堆栈信息,可以判断cpu占用率过高、死循环、死锁的情况

  命令:jstack -l 进程ID

 

常识或需要储备知识在文章最后~

 

 

一、常用工具详情:

1、jps (JVM Process Status Tool)

列出当前运行的所有java进程的ID

 

1):疑惑- wins 不是有任务管理器可以查看所有的进程,为啥还要jps?

 答:虽然windows任务管理器可以查看所有的进程,是因为当不止一个java进程时,使用win10的任务管理器,很难区分他们;而且win10的工具只能看到进程,看不到线程,所以需要其他工具

 

2):jps 测试案例:

package jps;

import java.io.IOException;

/**
 * ❀掌握:使用 jps命令查看java进程的ID 
 * 命令:jps
 * 直接输入jps (相当于 jps -V )
 * 
 * 
 * 
命令格式: jps[options][hostid]
第一个参数options   [-mlvV]可以任意组合使用
第二个参数:hostid
主机或者是服务器的ip,如果不指定,就默认为当前的主机或者是服务器。
注意:如果需要查看其他机器上的jvm进程,需要在待查看机器上启动jstatd。
 * 
 * jps + 
 * -q: 显示进程ID
 * -m: 显示进程ID,主类名称,以及传入main方法的参数
 * -l: 显示进程ID,主类全名【全限定名】
 * -v: 显示进程ID,主类名称,以及传入jvm的参数
 * -V: 显示进程ID,主类名称[❀]
 * @author Huangyujun
 *
 *-Xmn8m 指定年轻代内存大小
 */
public class jpsDemo {
    public static void main(String[] args) throws IOException {
        System.out.println("jps");
        System.in.read();
    }
}

 

打开终端查看:

 

测试 jps -m 命令前需要先设置面方法传递参数:

----------【具体步骤】在自己书写的测试类,右键->Run as -> Run Configurations… ->

 

2、jstat(JVM Statistics Monitoring Tool)

查看虚拟机运行数据------类装载、内存、垃圾收集、JIT编译 -----内存泄露或者内存溢出的判断使用命令之前需要给虚拟机设置参数

---因为控制台输入gc日志的前提:配置一下jvm的参数

例如:-Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc -XX:SurvivorRatio=8

 * -Xms20M 堆的初始容量     -Xmx20M 堆的最大容量    -Xmn10M 堆中年轻(新生)代的大小

 * -XX:+UseSerialGC 指定垃圾收集器SerialGC(串型垃圾回收器)   -XX:+PrintGCDetails 打印内存中GC的行为

   -verbose:gc 显示GC的情况        

 * -XX:ServivorRatio=8   设置 New Generation新生代中的 Eden区与Servivor区比例是8:1

 

命令: jstat -gc 进程ID  或者 jstat -gcutil 进程ID   判断是否内存泄露或者内存溢出 [这个需要懂点内存jvm收集机制]:

  可以看文章(里边有演示怎么判断)--或者那本经典的书《深入理解Java虚拟机》;文章:《奇怪的GC (Allocation Failure)日志 - 简书 (jianshu.io)》    

 

案例:

package jstat;

import java.io.IOException;

/**
 * -gc 选项:垃圾收集的堆统计信息
S0C、S1C:幸存区容量                                                                S0C:当前幸存者空间0容量(kB)    S1C:当前生存空间1的容量(kB)
S0U、S1U:❀堆内存中幸存区使用的容量                                      S0U:幸存者空间0使用大小(kB)     S1U:幸存者空间1使用大小(kB)
EC、EU:伊甸园容量   伊甸园使用的容量                              EC:当前伊甸园空间容量(kB)          EU:伊甸园空间使用大小(kB)
OC、OU:❀老年代容量、老年代使用的容量                              OC:当前的老年代容量(kB)              OU:老年代使用大小(kB)
方法区的使用情况:MC、MU:元空间容量、元空间使用的容量                   MC:元空间容量(kB)                          MU:元空间使用大小(kB)
压缩类的情况:CCSC:压缩的类空间容量(kB) CCSU:使用的压缩类空间(kB)

● 垃圾回收:●
● YGC:新生代垃圾收集事件的数量
● YGCT:新生代垃圾回收时间
● FGC:完整GC事件的数量
● FGCT:完整的垃圾收集时间
● GCT:总垃圾收集时间
==================================================
jstat -gc 线程ID 
jstat -gcutil 线程ID
■ gc 和 gcutil 区别:gc显示的是大小, gcutil 显示的是占比
===================================================
 * @author Huangyujun 
 * -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc -XX:SurvivorRatio=8 
 * -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc 
 * -Xms20M 堆的初始容量     -Xmx20M 堆的最大容量    -Xmn10M 堆中年轻(新生)代的大小
 * -XX:+UseSerialGC 指定垃圾收集器SerialGC(串型垃圾回收器)   -XX:+PrintGCDetails 打印内存中GC的行为     -verbose:gc 显示GC的情况
 * -XX:ServivorRatio=8    设置 New Generation新生代中的 Eden区与Servivor区比例是8:1
 */
public class gc_gcutil {
    //前提:配置一下vm的参数[JVM 配置]
    //GC(Allocation Failure)[DefNew: 7072k->(956k),0.0042301 secs...][Times:user=0.01 sys=0.00, real=0.01secs]...
    public static void main(String[] args) throws IOException {
        final int _1MB = 1024 * 1024;
        byte[] b1 = new byte[2 * _1MB];
        System.out.println("1...");
        System.in.read();//阻塞程序,当控制台输入回车键后继续执行
        
        byte[] b2 = new byte[2 * _1MB];
        System.out.println("2...");
        System.in.read();
        
        byte[] b3 = new byte[2 * _1MB];
        System.out.println("3...");
        System.in.read();
        
        byte[] a4= new byte[4*_1MB];
        
    }
}

/**
-gcutil 选项: 垃圾收集统计信息
    S0:幸存者空间0利用率占该空间当前容量的百分比
    S1:幸存者空间1利用率占空间当前容量的百分比
    E:Eden空间利用率占空间当前容量的百分比
    O:老年代利用率占空间当前容量的百分比
    M:元空间利用率占空间当前容量的百分比
    CCS:压缩的类空间利用率,以百分比表示
    YGC:新生代GC事件的数量
    YGCT:新生代垃圾回收时间
    FGC:完整GC事件的数量
    FGCT:完整的垃圾收集时间
    GCT:总垃圾收集时间
*/

 

3、jstack (Stack Trace forJava)  

查看或导出 Java 应用程序中线程堆栈信息,可以判断cpu占用率过高、死循环、死锁的情况

❀ 命令:jstack -l 进程ID

 

1)cpu占用率过高:

          1.使用Process Explorer工具,找到CPU占用率高的进程的id

​      2.右击该进程,查看属性,在thread选项卡中,找到cpu占用率高的线程id

​      3.把线程id转换成16进制

​      4.使用jstack -l 查看进程的线程快照

​      5.在线程快照中找到指定的线程,并分析代码

----通过工具,知道那个线程占用率高,然后在eclipse或者idea找到该占用率高的线程,从而知道占用率高的代码位置。

 

图1:使用Process Explorer工具,找到CPU占用率高的进程的id;右击该进程,查看属性,在thread选项卡中,找到cpu占用率高的线程id

 

图2:把线程id转换成16进制

 

图3:使用jstack -l 查看进程的线程快照;在线程快照中找到指定的线程,并分析代码

 

案例(代码):

package jstack;

import java.io.IOException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * jstack应用
 * @author Huangyujun
 *
 */
public class jstackTest {
    public static void main(String[] args) {
        System.out.println("start");
//        test1();
//        test2();
        test3();
        
        System.out.println("end");
    }
    //死循环
    public static void test1() {
        while(true) {}
    } 
    //等待控制台输入
    public static void test2() {
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    } 
    //死锁【我醒来了,我的锁被你拿了,你睡了;你醒来了,你的锁被我拿了,我睡了-------我等你,你等我【等不到的人】】
    public static void test3() {
        Lock lock1 = new ReentrantLock();
        Lock lock2 = new ReentrantLock();
        new Thread(() -> {
            try {
                lock1.lock();
                Thread.sleep(100);
                lock2.lock();//需要加锁,但是加锁失败,锁被另外一个线程myThread2持有
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "myThread1").start();
        new Thread(() -> {
            try {
                lock2.lock();
                Thread.sleep(100);
                lock1.lock();//通过lock1加锁,失败,等待锁的释放,按照提示说是被myThread1持有,观察发现:myThread1中:lock1.lock(); Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "myThread2").start();
        
    } 
}

 

//死循环

//等待控制台输入

//死锁

 

 

 

常识或需要储备知识~

1、System.in.read(); //让程序阻塞

2、Terminal 终端(方便,推荐) 也可以用win10的cmd控制台【dos窗口】

3、控制台输入gc日志的前提:配置一下jvm的参数[JVM 配置]

4、dos命令和进程命令相关的:

■ 常识----dos命令:

DOS命令,是操作系统的命令,是一种面向磁盘的操作命令,主要包括 目录操作类命令、磁盘操作类命令、文件操作类命令和其它命令。

✿ 常用操作----进程ID的查看与消灭进程:

1,cmd查看所有进程:netstat -ano

2,查看特定端口号的进程[例如:8080]: netstat -ano|findstr 8080

3,杀死对应的PID号对应的线程:taskkill /f /pid PID号

 

 

 

 

 

 

分类:

后端

标签:

Java

作者介绍

1一乐
V1