一文带你读懂JDK源码:JVM常用性能监控指令

点击上方 蓝字 关注我们

我们日常给系统定位问题,依据的是系统运行时的各项指标数据和工具,数据包括了:运行日志、异常堆栈、GC日志、线程快照、堆转储快照等;而工具则包括了:监视虚拟机和故障处理的工具。

这些故障处理工具是Sun公司赠与我们开发者的独特“礼物”,它们功能强大且稳定,帮助我们更好的处理应用程序性能问题和定位故障。

下文主要介绍了6个常用的监控工具:

  • jps :JVM Process Status Tool,一款用于查看java进程的工具 - 查看当前环境下运行的java服务的进程id和名称

  • jstat :JVM Statistics Monitoring,一款用于监视虚拟机各种运行状态统计信息工具。

  • jinfo :Configuration Info For Java,一款用于实时查看和修改JVM参数的工具。

  • jmap :Memory Map for Java,一款用于生成堆转储快照即dump文件的命令。

  • jhat :JVM Heap Analysis Tool,一款用来分析dump文件的工具。

  • jstack :Stack Trace for Java,一款用于生成当前时刻的线程状态信息的快照工具。

winter

开讲前,我们先回顾下JVM的基本结构。根据《Java虚拟机规范(Java SE 7版)》。Java虚拟机所管理的内存将会包括以下几个运行时数据区域:

  • 程序计数器(Program Counter Register):当前线程执行的字节码指示器

  • Java虚拟机栈(Java Virtual Machine Stacks):Java方法执行的内存模型,每个方法会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

  • 本地方法栈(Native Method Stack):(虚拟机使用到的)本地方法执行的内存模型。

  • Java堆(Java Heap):虚拟机启动时创建的内存区域,唯一目的是存放对象实例,处于逻辑连续但物理不连续内存空间中。

  • 方法区(Method Area):存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。运行时常量池(Runtime Constant Pool)是方法区的一部分,存放编译器生成的各种字面值和符号引用。

一文带你读懂JDK源码:JVM常用性能监控指令_第1张图片

JVM进程工具:jps

jps 工具:JVM Process Status Tool,一款用于查看java进程的工具。功能是查看当前环境下运行的java服务的进程id和名称,一般其他命令使用前都会先使用jps命令获取java进程信息。

指令格式:jps [options] [hostid]

 [options]的参考列表:

一文带你读懂JDK源码:JVM常用性能监控指令_第2张图片

代码demo:

  /**
   * 

* jps 指令 启动参数:-Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError *

*/ private static void testJPS() throws InterruptedException { ArrayList objects = new ArrayList<>(); for (int i = 0; i < 10000000; i++) { Integer integer = new Integer(i); objects.add(integer); System.out.println("sleeping.. i = " + i); Thread.sleep(100); } }

指令执行:jps -l

一文带你读懂JDK源码:JVM常用性能监控指令_第3张图片

JVM状态工具:jstat

jstat 工具:可以进一步对该 JVM 的各种运行状态信息进行捕获(显示本地或者远程JVM的类装载、内存、垃圾收集JIT编译等数据)。

指令格式:jstat [options] [hostid] [gap-扫描间隔] 

 [options] 的参考列表:

一文带你读懂JDK源码:JVM常用性能监控指令_第4张图片

代码demo:

  /**
   * 

* jstat 指令 * 案例: * 启动参数:-Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError * 内存最终溢出OOM,此时通过jstat可以观察到进行了8次YGC,1次FGC *

*/ private static void testJSTAT() throws InterruptedException { ArrayList objects = new ArrayList<>(); ArrayList objects2 = new ArrayList<>(); for (int i = 0; i < 10000000; i++) { Integer integer = new Integer(i); objects.add(integer); System.out.println("sleeping.. i = " + i); objects2.addAll(objects); if (i > 830) { Thread.sleep(100); } } }

指令执行:jstat -gc 19345 3550 (每隔3550ms扫描一次内存使用情况,内存最终溢出OOM,此时通过jstat可以观察到进行了8次YGC,1次FGC)

一文带你读懂JDK源码:JVM常用性能监控指令_第5张图片

结果分析:注意:C表示Capacity(容量),U表示Used(已使用大小)

序号
字段
含义
1
S0C
第一个幸存区的大小
2 S0C
第一个幸存区的大小
3
S0U
第二个幸存区的使用大小
4 S1U
第二个幸存区的已使用大小
5 EC
Eden区的大小
6 EU
Eden区的已使用大小
7
OC
老年代的大小
8 OU
老年代已使用大小
9
MC
方法区大小
10
MU
方法区使用大小
11 CCSC
压缩类空间大小
12 CCSU
压缩类空间使用大小
13 YGC
年轻代垃圾回收次数
14
YGCT
年轻代垃圾回收消耗时间
15 FGC
老年代垃圾回收次数
16
FGCT
老年代垃圾回收消耗时间
17
GCT
垃圾回收消耗总时间

JVM参数配置工具:jinfo

jinfo 工具:可以实时查看和调整虚拟机的各项参数。

指令格式:

jinfo -flag name [PID]: 查看某个java进程的name属性的值
     jinfo -flags [PID]: 查看已经赋值的JVM参数

代码demo:

  /**
   * 

* jinfo 指令 * 可以实时查看和调整虚拟机的各项参数 * 配置:-Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError * 案例: *

*/ private static void testJINFO() throws InterruptedException { ArrayList objects = new ArrayList<>(); for (int i = 0; i < 1000; i++) { Integer integer = new Integer(i); objects.add(integer); System.out.println("sleeping.. i = " + i); Thread.sleep(100); } }

指令执行:jinfo -flag

一文带你读懂JDK源码:JVM常用性能监控指令_第6张图片

JVM内存映像工具:jmap

jmap 指令:用于生成堆转储快照(又叫 heapdump 或 dump 文件)。

指令格式:

jmap -heap [PID] //打印出堆内存相关信息

jmap -dump:format=b,file=/usr/heap.hprof  [PID] //生成dump文件

通用配置:-XX:+HeapDumpOnOutOfMemoryError

一旦发生OutOfMemoryError之后就会自动生成dump文件。

代码demo:

  /**
   * 

* jmap 指令 * 获取dump文件,还能查询 finalize 执行队列、Java 堆和永久代的信息(空间使用率&GC收集器等) * 配置:-Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError *

*/ private static void testJMAP() throws InterruptedException { ArrayList objects = new ArrayList<>(); for (int i = 0; i < 1000; i++) { Integer integer = new Integer(i); objects.add(integer); System.out.println("sleeping.. i = " + i); Thread.sleep(100); } }

指令执行:jmap -dump:format=b,file=testjmap.bin 20136

一文带你读懂JDK源码:JVM常用性能监控指令_第7张图片

生成文件默认位置:

一文带你读懂JDK源码:JVM常用性能监控指令_第8张图片

JVM堆转储快照分析工具:jhat

jhat 指令:与 jmap 搭配使用,用来分析 jmap 生成的堆转储快照。

指令格式: jhat [filename] 

指令执行:jhat testjmap.bin

一文带你读懂JDK源码:JVM常用性能监控指令_第9张图片

JVM堆栈跟踪工具:jstack

jstack 指令:用于生成虚拟机的线程快照(又叫threaddum 或者 javacore 文件)。

指令格式:jstack [options] [PID]

指令执行:jstack -l 20024

一文带你读懂JDK源码:JVM常用性能监控指令_第10张图片

JDK可视化工具JConsole

JConsole:Java Monitoring and Management Console,是一款JDK自带的可视化监控工具。

通过 jconsole 可以查看java应用程序的运行概况、监控堆信息、永久区使用情况、类加载情况等信息。

步骤1、选择监控的JVM进程

一文带你读懂JDK源码:JVM常用性能监控指令_第11张图片

步骤2、通过控制台的各个tab可以查看进程的详情(JVM概览 / 内存分区使用情况等)

一文带你读懂JDK源码:JVM常用性能监控指令_第12张图片

案例1:通过可视化工具,监控内存使用情况



  /**
   *  JConsole 可视化监控
   *  启动配置:-Xms100m -Xmx100m -XX:+UseSerialGC
   *  -Dcom.sun.management.jmxremote  -Dcom.sun.management.jmxremote.port=8077
   *  -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
   *  案例:
   *    每50ms一次往Java堆填充64Kb数据,一共1000次
   */
  private static void testJCONSOLE() throws InterruptedException {
    ArrayList list = new ArrayList<>();
    for (int i = 0; i < 1000; i++){
      //延时一段时间,让监控曲线变得明显。
      Thread.sleep(50);
      list.add(new OOMObject());
    }
    System.gc();
  }


  /**
   * 内存占位符对象,一个对象 64KB
   */
  static class OOMObject{
    public byte[] placeholder = new byte[64*1024];
  }

JVM内存分析:程序每50ms一次往Java堆填充64Kb数据,一共1000次,同时因为Eden区超出阈值会触发YoungGC,导致Eden的大小呈高低波浪变化。

一文带你读懂JDK源码:JVM常用性能监控指令_第13张图片

案例2:通过可视化工具,完成死锁问题的定位

  /**
   * 

* 案例:死锁演示 *

*/ private static void testJCONSOLE_DeadLock() { for (int i = 0; i <100; i++){ new Thread(new SynAddRunnable(1,2)).start(); new Thread(new SynAddRunnable(2,1)).start(); } } /** *

* 线程死锁等待演示 *

*/ static class SynAddRunnable implements Runnable{ int a,b; public SynAddRunnable(final int a, final int b) { this.a = a; this.b = b; } @Override public void run() { synchronized (Integer.valueOf(a)){ synchronized (Integer.valueOf(b)){ System.out.println(a + b); } } } }

JVM内存分析:Thread-1 与 Thread-2 两个线程由于互相资源等待,所以导致了死锁。

一文带你读懂JDK源码:JVM常用性能监控指令_第14张图片

一文带你读懂JDK源码:JVM常用性能监控指令_第15张图片

总结

总结一下,本节共介绍了6个JVM性能监控指令,同时也介绍了一个JDK内置的可视化工具JConsole,该工具有助于开发者,去直观的分析JVM的性能问题。希望对大家理解JVM的内存监控有所帮助~

一文带你读懂JDK源码:JVM常用性能监控指令_第16张图片

往期推荐

《源码系列》

《JDK之Object 类》

《JDK之BigDecimal 类》

《JDK之String 类》

《JDK之Lambda表达式》

《Spring源码:Event事件发布与监听》

《JDK之ThreadPoolExecutor线程池》

《JDK之JVM的5种锁优化方式》

《经典书籍》

《Java并发编程实战:第1章 多线程安全性与风险》

《Java并发编程实战:第2章 影响线程安全性的原子性和加锁机制》

《Java并发编程实战:第3章 助于线程安全的三剑客:final & volatile & 线程封闭》

《服务端技术栈》

《Docker 核心设计理念》

《Kafka史上最强原理总结》

《HTTP的前世今生》

《Mysql的核心知识点》

《算法系列》

《读懂排序算法(一):冒泡&直接插入&选择比较》

《读懂排序算法(二):希尔排序算法》

《读懂排序算法(三):堆排序算法》

《读懂排序算法(四):归并算法》

《读懂排序算法(五):快速排序算法》

《读懂排序算法(六):二分查找算法》

《设计模式》

《设计模式之六大设计原则》

《设计模式之创建型(1):单例模式》

《设计模式之创建型(2):工厂方法模式》

《设计模式之创建型(3):原型模式》

《设计模式之创建型(4):建造者模式》

《设计模式之创建型(5):抽象工厂设计模式》

《设计模式之结构型(1):代理类设计模式》

扫描二维码

获取技术干货

后台技术汇

一文带你读懂JDK源码:JVM常用性能监控指令_第17张图片

点个“在看”表示朕

已阅

你可能感兴趣的:(jvm,java,多线程,jdk,内存泄漏)