1.检查体系进程 JPS指令

JPS检查体系进程信息 28532 G1Test 表明进程Pid28532 的进程姓名是G1Test

E:\setup\jar>jps
39024 Launcher
42832 Jps
22644
28532 G1Test
43020 RemoteMavenServer36
9756 Launcher

和咱们程序的运行是保持一致的, 咱们的程序名称便是G1Test

JVM系列(二十) JVM调优实战-常用命令Jps/PS/Jinfo/Jstat实战

2.检查进程信息 ps -ef |grep xxx

Linux体系中,咱们能够运用 ps指令来检查详细的进程信息

#检查体系 java 进程信息
ps -ef |grep java
#检查详细项目的进程信息
ps -ef |grep web-gateway

履行成果

[saas@dev-119 ~]$ ps -ef |grep web-gateway
saas      7039  5764  0 14:33 pts/0    00:00:00 grep --color=auto web-gateway
root     25030 25009  0 3月27 ?       00:00:00 /bin/bash /xxx/app/web-gateway/web-gateway.sh
root     25097 25030  3 3月27 ?       17:34:15 java -server 
-Dspring.profiles.active=docker 
-DskipTests -Dfile.encoding=UTF-8 
-Dsun.jnu.encoding=UTF-8 
-Duser.timezone=GMT+8 
-Djava.net.preferIPv6Addresses=false -agentlib:jdwp=transport=dt_socket,address=20112,server=y,suspend=n -Xms2g -Xmx2g -Ddubbo.registry.address=zoo1:2181,zoo2:2181 
-Dspring.cloud.nacos.config.namespace=xxx 
-Dsso-env=xxx 
-Dspring.cloud.nacos.discovery.group=xxx 
-DxxxUrl=https://sso119.devtest.vip 
-DxxxUrl=https://xxx 
-DxxxUrl=https://xxx 
-DxxxUrl=https://xxx 
-DxxxUrl=https://xxx 
-jar /xxx/web-gateway/web-gateway.jar

3.jinfo pid 指令检查进程信息

咱们经过 jps 或许经过 ps-ef |grep xxx 都是为了找到进程信息,找到之后 有什么用 ? 咱们能够经过进程信息,检查进程参数 jinfo指令

#检查进程详细参数, 履行 jinfo pid进程id
jinfo 36612

履行成果

E:\setup\jar>jinfo 36612
Attaching to process ID 36612, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.181-b13
Java System Properties:
java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.181-b13
sun.boot.library.path = C:\xxxxx
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = ;
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
sun.os.patch.level =
sun.java.launcher = SUN_STANDARD
user.script =
user.country = CN
user.dir = E:xxxxx
java.vm.specification.name = Java Virtual Machine Specification
java.runtime.version = 1.8.0_181-b13
java.awt.graphicsenv = sun.awt.Win32GraphicsEnvironment
os.arch = amd64
java.endorsed.dirs = C:\xxxxx
line.separator =
java.io.tmpdir = C:\xxxxx
java.vm.specification.vendor = Oracle Corporation
user.variant =
os.name = Windows 10
sun.jnu.encoding = GBK
java.library.path = xxxxx
java.class.version = 52.0
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
os.version = 10.0
user.home = C:\Users\jzj
user.timezone = Asia/Shanghai
java.awt.printerjob = sun.awt.windows.WPrinterJob
file.encoding = UTF-8
java.specification.version = 1.8
user.name = jzj
java.class.path =xxxxx
java.vm.specification.version = 1.8
sun.arch.data.model = 64
sun.java.command = com.jzj.jvmtest.jvmready.G1Test
java.home = C:\xxxxx
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.windows.WToolkit
java.vm.info = mixed mode
java.version = 1.8.0_181
java.ext.dirs = xxxxx
file.separator = \
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64
VM Flags:
Non-default VM flags: -XX:CICompilerCount=4 -XX:ConcGCThreads=3 -XX:G1HeapRegionSize=1048576 -XX:+HeapDumpOnOutOfMemoryError -XX:InitialHeapSize=10485760 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=10485760 -XX:MaxNewSize=6291456 -XX:MinHeapDeltaBytes=1048576 -XX:+PrintGC -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:-UseLargePagesIndividualAllocation
Command line:  -verbose:gc -XX:+UseG1GC -Xms10M -Xmx10M -XX:+PrintGC -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:SurvivorRatio=8 -javaagent:E:\Program Files\JetBrains\IntelliJ IDEA 2019.3.4\lib\idea_rt.jar=58937:E:\Program Files\JetBrains\IntelliJ IDEA 2019.3.4\bin -Dfile.encoding=UTF-8
3.1 体系变量

悉数的java体系变量等等

  • java.version java版别
  • user.name 用户姓名
  • user.timezone = Asia/Shanghai 时区信息
  • java.io.tmpdir = C:\xxxxx 临时文件寄存途径
java.home = C:\xxxxx
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.windows.WToolkit
java.vm.info = mixed mode
java.version = 1.8.0_181
java.ext.dirs = xxxxx
3.2 JVM参数

VM虚拟机参数 VM Flags

  • -XX:G1HeapRegionSize 每个Region的大小,单位MB,需要为1,2,4,8,16,32其一,默认是堆内存的1/2000
  • -XX:InitialHeapSize=10485760 等同于 -Xms设置,表明Heap的初始化大小,即JVM启动时,堆区的最小值
  • -XX:HeapDumpOnOutOfMemoryError 堆栈溢出打印OOM错误
  • -XX:MaxNewSize=6291456 JVM堆区域新生代内存的最大可分配大小(PermSize不属于堆区)
  • -XX:+UseG1GC 运用G1废物搜集器
  • -XX:MinHeapDeltaBytes=1048576 表明当咱们要扩容或许缩容的时分,决议是否要做或许尝试扩容的时分最小扩多少
  • -XX:+PrintGCDetails GC时分打印概况
  • -XX:SurvivorRatio=8 年青到和survivor比例是 1:1:8 (s0:s1:Eden)
  • XX:MaxHeapSize=10485760 最大的堆内存分配
VM Flags:
Non-default VM flags: -XX:CICompilerCount=4 -XX:ConcGCThreads=3 -XX:G1HeapRegionSize=1048576 -XX:+HeapDumpOnOutOfMemoryError -XX:InitialHeapSize=10485760 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=10485760 -XX:MaxNewSize=6291456 -XX:MinHeapDeltaBytes=1048576 -XX:+PrintGC -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:-UseLargePagesIndividualAllocation

4.jstat指令

jstat是JDK自带的轻量级小工具,专门用于监控JVM的GC状况,对Java应用程序的资源和功能进行实时的指令行的监控,包含了对Heap size和废物收回状况的监控,咱们先看看有哪些指令能够运用

#履行 jstat options
E:\setup\jar>jstat -options
-class
-compiler
-gc
-gccapacity
-gccause
-gcmetacapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcutil
-printcompilation

咱们对指令进行结束

  • class 用于检查类加载状况的计算
  • compiler 用于检查HotSpot中即时编译器编译状况的计算
  • gc 用于检查JVM中堆的废物搜集状况的计算常常运用
  • gccapacity 用于检查新生代、老生代及持久代的存储容量状况常常运用
  • gcmetacapacity 显现metaspace的大小及信息常常运用
  • gcnew 用于检查新生代废物搜集的状况
  • gcnewcapacity 用于检查新生代存储容量的状况
  • gcold 用于检查老生代及持久代废物搜集的状况
  • gcoldcapacity 用于检查老生代的容量
  • gcutil 显现废物收回信息常常运用
  • gccause 显现废物收回的相关信息(同-gcutil), 一起显现最终一次仅当时正在发生的废物搜集的原因
  • printcompilation 输出JIT编译的办法信息

启动程序

@Slf4j
public class G1Test {
    //JVM 参数 -verbose:gc -Xms10M -Xmx10M  -XX:+PrintGC -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:SurvivorRatio=8
    public static void main(String[] args) throws Exception {
        byte[] b = null;
        for (int i = 1; i <= 20; i++) {
            //设置 3M的目标
            log.info("======== " + i + "次添加3M目标");
            b = new byte[2 * 1024 * 1024];
            Thread.sleep(3000);
        }
    }
}
4.1 jstat -gc pid 检查进程 GC状况

先履行 jps 找到进程PID G1Test PID是 25060

E:\setup\jar>jps
45616 Launcher
22644
25060 G1Test
44308 Jps

履行jstat -gc 25060

#履行 jstat -gc pid
E:\setup\jar>jstat -gc 25060
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
 0.0   1024.0  0.0   1024.0  3072.0    0.0      6144.0     5777.7   5504.0 5088.0 640.0  565.8       2    0.003   0      0.000    0.003
 #履行 jstat -gc pid 参数1(多少秒履行1次) 参数2 总共打印多少次
 #履行 jstat -gc 25060 1000  3 ,表明 1000ms履行1次, 总共履行 3次
 E:\setup\jar>jstat -gc 25060 1000 3
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
 0.0   1024.0  0.0   1024.0  3072.0    0.0      6144.0     5777.7   5504.0 5088.0 640.0  565.8       2    0.003   0      0.000    0.003
 0.0   1024.0  0.0   1024.0  3072.0    0.0      6144.0     5777.7   5504.0 5088.0 640.0  565.8       2    0.003   0      0.000    0.003
 0.0   1024.0  0.0   1024.0  3072.0    0.0      6144.0     5777.7   5504.0 5088.0 640.0  565.8       2    0.003   0      0.000    0.003

咱们解释一下这些信息S0C/S1C/S0U等等代表什么意思

年青代 幸存区S0/S1 及Eden区的运用状况(单位字节Byte)

S0C S1C S0U S1U EU EC
年青代幸存区From区S0的 容量Capacity 年青代幸存区To区S1的 容量Capacity 年青代幸存区From区S0现已运用Use的容量Capacity 年青代幸存区To区S1的 现已运用Use的容量Capacity 年青代Eden区的容量Capacity 年青代Eden区现已运用Used的容量Capacity

老时代Old区,元空间Metaspace及CCS(当时压缩类)的运用状况 (单位字节Byte)

OC OU MC MU CCSU CCSU
Old老时代 容量Capacity Old老时代现已运用Use的容量Capacity 元空间Metaspace 容量Capacity 元空间Metaspace现已运用Use的容量Capacity 当时压缩类空间 容量Capacity 当时压缩类空间现已运用Used的容量Capacity

YoungGC,FullGC发生的次数及花费的时刻(秒/s)状况

YGC YGCT FGC FGCT GCT
从程序启动到采样,YoungGC 发生的次数 从程序启动到采样,YoungGC 花费的时刻 从程序启动到采样,FullGC 发生的次数 从程序启动到采样,FullGC 花费的时刻 从程序启动到采样,GC总共用时
4.2 jstat -gcutil pid 检查进程 GC废物收回状况

履行JPS找到进程PID G1Test PID 44788

E:\setup\jar>jps
22644
44788 G1Test
47492 Jps
35992 Launcher

履行 jstat -gcutil 44788 1000 10 检查废物收回状况 1000ms 打印一次, 总共打印10次

#履行 jstat -gcutil 44788 1000 10 
E:\setup\jar>jstat -gcutil 44788 1000 10
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00   0.00   0.00  65.24  94.24  89.56     20    0.081     4    0.037    0.118
  0.00   0.00   0.00  65.24  94.24  89.56     21    0.081     4    0.037    0.118
  0.00   0.00   0.00  65.35  94.24  89.56     21    0.092     4    0.037    0.129
  0.00   0.00   0.00  65.35  94.24  89.56     21    0.092     4    0.037    0.129
  0.00 100.00   0.00  31.89  94.24  89.56     23    0.100     5    0.037    0.137
  0.00   0.00   0.00  86.70  94.24  89.56     23    0.100     5    0.049    0.149
  0.00   0.00   0.00  86.70  94.24  89.56     23    0.100     5    0.049    0.149
  0.00 100.00   0.00  70.10  94.24  89.56     24    0.103     5    0.049    0.152
  0.00 100.00   0.00  70.10  94.24  89.56     24    0.103     5    0.049    0.152
  0.00 100.00   0.00  70.10  94.24  89.56     24    0.103     5    0.049    0.152

咱们解释一下这些信息 S0/S/E/O/M/CCS/YGC/YGCT/FGC/FGCT/GCT 等代表什么意思

首先说明一点 这儿打印出来的不是实在运用的容量Byte,而是为了便利检查,运用的是 百分比占比,愈加直观,便利定位问题

S0 S1 E O M CCS
年青代幸存区From区S0 已运用占当时容量的百分比 年青代幸存区From区S1 已运用占当时容量的百分比 Eden区现已运用占当时容量的百分比 Old老时代现已运用占当时容量的百分比 元空间Metaspace现已运用占当时容量的百分比 当时压缩类空间现已运用占当时容量的百分比

从上面能够看出来什么问题? 咱们看下这两次打印

#履行 jstat -gcutil 44788 1000 10 
E:\setup\jar>jstat -gcutil 44788 1000 10
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00   0.00   0.00  65.35  94.24  89.56     21    0.092     4    0.037    0.129
  0.00 100.00   0.00  31.89  94.24  89.56     23    0.100     5    0.037    0.137
  1. YGC从 21->23 说明1s之内发生了2次YoungGC,FGC从 4->5说明1s之内发生了1次FullGC
  2. YGC/FullGC后,S0区域开始向S1区域复制存活的目标,导致S1占比100%
  3. 说明YounGC后,需要复制的东西很多,从From转移到To区
  4. Old区从65%->31%, 老时代部分目标经历过FullGC后被销毁
  5. Metaspace 占比94.24% 元空间太小了,即将要占满
4.3 jstat -gccause pid 检查gc原因

履行JPS找到进程PID G1Test PID 44912

E:\setup\jar>jps
44912 G1Test
22644
37180 Launcher
46220 Jps

履行 jstat -gccause 44912 检查gc引起的原因

E:\setup\jar>jstat -gccause 44912
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC
  0.00   0.00   0.00  86.70  94.22  89.56     13    0.045     3    0.017    0.062 Allocation Failure   No GC
  • LGGC 最终一次GC的原因 Allocation Failure 内存分配失败导致
  • GCC 当时GC原因 No GC 为当时没有履行GC
E:\setup\jar>jstat -gccause 44912
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC
  0.00 100.00   0.00  70.07  94.22  89.56     19    0.066     4    0.023    0.089 G1 Humongous Allocation No GC
  • LGGC 最终一次GC的原因 G1 Humongous Allocation G1的大目标分配导致
  • GCC 当时GC原因 No GC 为当时没有履行GC

至此 咱们学习了基本的JVM调优指令包含JPS检查进程,jinfo检查进程详细参数,Jstat检查JVM gc状况,特别是jstat的轻量级JVM调优小工具运用,咱们依据详细的日志,来剖析JVM发生GC的原因,进行JVM调优