JVM调优工具详解及调优实战(1)

文章目录

    • 1. 前提准备
    • 2. Jmap
    • 3. Jstack
    • 4. Jinfo
    • 5. Jstat(重点)
    • 6. 案例分析

1. 前提准备

任意启动一个web项目,这里我已经启动好了
JVM调优工具详解及调优实战(1)_第1张图片

2. Jmap

map命令用于生成堆转储快照,有时候也成为heapdump或者dump文件。Jmap不仅仅可以获取dump文件,还可以查询finalize执行队列,Java堆和永久代的详细信息,如空间使用率、当时用的是那种收集器等。

使用jps查看我们的进程号为99646

jps

JVM调优工具详解及调优实战(1)_第2张图片

使用jmap查看信息

jmap -histo 99646

JVM调优工具详解及调优实战(1)_第3张图片

发现终端查看信息比较不清楚,我们可以将输出放入到一个日志文件中

jmap -histo 99646 > ./log.txt

JVM调优工具详解及调优实战(1)_第4张图片

  • num:序号
  • instances:实例数量
  • bytes: 占用空间大小
  • class name: 类名称

查看堆信息

 jmap -heap 99646

导出堆的快照,并可以将快照导入到jvisualvm分析

jmap -dump:format=b,file=eureka.hprof 99646

JVM调优工具详解及调优实战(1)_第5张图片

3. Jstack

jstack命令用于打印指定Java进程、核心文件或远程调试服务器的Java线程的Java堆栈跟踪信息。jstack命令可以生成JVM当前时刻的线程快照。线程快照是当前JVM内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。

下面模拟程序死锁情况,线程获得锁1然后想获得锁2,线程2获得锁2然后想获得锁1,这样会出现相互等待而产生死锁

public class jvmtestMain {
        private static Object lock1 = new Object();
        private static Object lock2 = new Object();
        public static void main(String[] args) {
            new Thread(()->{
                 synchronized (lock1) {
                    try{
                         System.out.println("thread1 begin");
                         Thread.sleep(5000);
                    } catch (InterruptedException e) { }
                    synchronized (lock2) {
                        System.out.println("thread1 end");
                    }
                 }}).start();
            new Thread(()->{
                synchronized (lock2) {
                    try{
                        System.out.println("thread2 begin"); Thread.sleep(5000);
                    } catch (InterruptedException e) { }
                     synchronized (lock1) { System.out.println("thread2 end"); }
            }}).start();
            System.out.println("main thread end");
        } 
}

jstack打印线程堆栈信息

 jstack 4276

JVM调优工具详解及调优实战(1)_第6张图片

4. Jinfo

jinfo是java虚拟机自带的Java配置信息工具,可以实时地查看和调整虚拟机的各项参数。

  • jinfo [ option ] pid 连接到正在运行的进程
  • jinfo [ option ] executable core 连接到核心文件
  • jinfo [ option ] [ servier-id ] remote-hostname-or-IP 要连接到远程DEBUG服务器
jinfo 6123

5. Jstat(重点)

jstat命令可以查看堆内各个部分的使用量就,以及加载类的数量,命令的格式如下:
jstat [-命令选项] [vmid][间隔时间(毫秒)][查询次数]

  • 垃圾回收统计
jstat -gc 21968

在这里插入图片描述

  • S0C:第一个幸存区的大小,单位KB
  • S1C:第二个幸存区的大小
  • S0U:第一个幸存区的使用大小
  • S1U:第二个幸存区的使用大小
  • EC:伊甸园区的大小
  • EU:伊甸园区的使用大小
  • OC:老年代大小
  • OU:老年代使用大小
  • MC:方法区大小(元空间)
  • MU:方法区使用大小
  • CCSC:压缩类空间大小
  • CCSU:压缩类空间使用大小
  • YGC:年轻代垃圾回收次数
  • YGCT:年轻代垃圾回收消耗时间,单位s
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间,单位s
  • GCT:垃圾回收消耗总时间,单位s
#表示我们要执行10次这个命令,且每隔1s钟执行1次
jstat -gc 21968 1000 10

6. 案例分析

系统频繁Full GC导致系统卡顿是怎么回事?

  • 机器内核:2核4G
  • JVM内存大小:2G
  • 系统运行时间:7天
  • 期间发生的Full GC次数和耗时:500多次 200多秒
  • 期间发生的Young GC次数和耗时:1万多次, 500多秒

大概算下来每天会发生70次Full GC,平局每小时3次,每次Full GC在400毫秒左右。每天会发生1000多次Young GC,每分钟会发生1次,每次Young GC在50毫秒左右

JVM参数配置如下:

-Xms1536M -Xmx1536M -Xmn512M -Xss256K -XX:SurvivorRatio=6 
-XX:MetaspaceSize=256M 
-XX:MaxMetaspaceSize=256M 
-XX:+UseParNewGC 
-XX:+UseConcMarkSweepGC 
-XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly

JVM调优工具详解及调优实战(1)_第7张图片

  1. 每分钟发生一次Young GC说明一个问题:每分钟Eden区就会被新对象放满,而触发Young GC,即线程运行每秒会产生6MB对象
  2. 每个小时产生3次Full GC:20分钟一次Full GC,意味着20分钟有700多M对象挪到老年代(CMSInitiatingOccupancyFraction=75 ),这也导致full GC的原因,且full GC把这些移动到老年代的对象基本都杀死了(因为每20分钟做一次full GC),可能的原因如下:
  • 大对象直接进入老年代(这得依据系统实际进行分析)
  • 长期存活对象直接进入老年代
  • 老年代担保机制
  • 动态年龄判断机制

你可能感兴趣的:(jvm)