jvm監(jiān)控與調(diào)優(yōu)之jdk命令行工具

jvm監(jiān)控與調(diào)優(yōu)之jdk命令行工具

目錄


jvm的參數(shù)類型

標(biāo)準(zhǔn)參數(shù)
  • -help
  • -server -client
  • -version -showversion
  • -cp -classpath
X參數(shù)
  • 非標(biāo)準(zhǔn)化參數(shù)(在各個(gè)JDK版本中可能會(huì)變,但是變動(dòng)比較小)
  • -Xint : 解釋執(zhí)行
//使用命令:java -Xint -version  jvm為interpreted mode(解釋執(zhí)行)
C:\Users\jeffrey>java -Xint -version
java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, interpreted mode)
  • -Xcomp : 編譯執(zhí)行 第一次使用就編譯成本地代碼
//使用命令:java -Xcomp -version  jvm為compiled mode(編譯執(zhí)行)
C:\Users\jeffrey>java -Xcomp -version
java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, compiled mode)
  • -Xmixed :混合模式,JVM自己來決定是否編譯成本地代碼
//使用命令:java -version jvm為mixed mode(混合模式)
C:\Users\jeffrey>java -version
java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)
XX參數(shù)
  • 非標(biāo)轉(zhuǎn)化參數(shù)
  • 相對不穩(wěn)定
  • 主要用于JVM調(diào)優(yōu)和Debug
  • 參數(shù)分類
    • Boolean 類型
      //格式:-XX:[+-]<name> 表示啟用或禁用name屬性
      //比如:
          -XX:+UseConcMarkSweepGC  //表示啟用CMS垃圾收集器([+]號代表啟用,[-]代表禁用)
          -XX:+UseGcG1        //表示啟用G1垃圾收集器
      
    • 非 Boolean 類型
      //格式:-XX:<name>=<value> 表示name屬性的值是value
      //比如:
          -XX:MaxGcPauseMillis=500 //GC的最大停頓時(shí)間是500毫秒
          -XX:GCTimeRatio=19    //設(shè)置吞吐量大小,它的值是一個(gè) 0-100 之間的整數(shù)。假設(shè) GCTimeRatio 的值為 n,那么系統(tǒng)將花費(fèi)不超過 1/(1+n) 的時(shí)間用于垃圾收集
      
-Xmx -Xms
  • 不是X參數(shù),而是XX參數(shù)
  • -Xms 等價(jià)于 -XX:InitialHeapSize 初始化的堆大小
  • -Xmx 等價(jià)于 -XX:MaxHeapSize 最大化的堆大小
  • jinfo -flag MaxHeapSize <進(jìn)程編號>
    //查詢所有java進(jìn)程
    [root@localhost ~]# ps -ef | grep java
    root      13220   9664  9 16:24 pts/1    00:00:08 java -jar spring-boot-test-0.0.1-SNAPSHOT.jar
    
    [root@localhost ~]# jinfo -flag MaxHeapSize 13220
    -XX:MaxHeapSize=515899392   //運(yùn)行時(shí)最大的堆大小
    
  • jinfo -flag ThreadStackSize <進(jìn)程編號>
    [root@localhost ~]# ps -ef | grep java
    root      13220   9664  9 16:24 pts/1    00:00:08 java -jar spring-boot-test-0.0.1-SNAPSHOT.jar
    
    [root@localhost ~]# jinfo -flag ThreadStackSize 13220
    -XX:ThreadStackSize=1024K   //啟動(dòng)一個(gè)線程需要的內(nèi)存大小
    

運(yùn)行時(shí)jvm參數(shù)查看

運(yùn)行時(shí)參數(shù)
  • -XX:+PrintFlagsInitial
  • -XX:PrintFlagsFinal
  • -XX:+UnlockExperimentalVMOptions 解鎖實(shí)驗(yàn)參數(shù)
  • -XX:+UnlockDiagnosticVMOptions 解鎖診斷參數(shù)
  • -XX:+PrintCommandLineFlags 打印命令行參數(shù)
//=表示默認(rèn)值
//:被用戶或者JVM修改過后的值
[root@localhost ~]# java -XX:+PrintFlagsFinal -version 
[Global flags]
     intx ActiveProcessorCount                      = -1                                  {product}
    uintx AdaptiveSizeDecrementScaleFactor          = 4                                   {product}
    uintx MaxHeapFreeRatio                          = 100                                 {manageable}
    uintx MaxHeapSize                              := 515899392                           {product}
    uintx MaxMetaspaceExpansion                     = 5451776                             {product}
    uintx MaxMetaspaceFreeRatio                     = 70                                  {product}
    uintx MaxMetaspaceSize                          = 18446744073709547520                    {product}
    uintx MaxNewSize                               := 171966464                           {product}
    uintx MaxRAMFraction                            = 4                                   {product}
    uintx MaxTenuringThreshold                      = 15                                  {product}
    uintx MinHeapDeltaBytes                        := 524288                              {product}
    uintx MinHeapFreeRatio                          = 0                                   {manageable}

//文件下載到本地查看
[root@localhost ~]# java -XX:+PrintFlagsFinal -version > falgs.txt
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)
[root@localhost ~]# sz falgs.txt 
jps

用來查看java進(jìn)程,參考網(wǎng)站:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jps.html#CHDCGECD

[root@localhost ~]# jps -l
17089 sun.tools.jps.Jps
7331 /usr/lib/jenkins/jenkins.war
13220 spring-boot-test-0.0.1-SNAPSHOT.jar
jinfo

jinfo是jdk自帶的命令,可以用來查看正在運(yùn)行的Java應(yīng)用程序的擴(kuò)展參數(shù),甚至支持在運(yùn)行時(shí),修改部分參數(shù)。

官網(wǎng)地址:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jinfo.html#BCGEBFDD

//查看最大內(nèi)存
[root@localhost ~]# jinfo -flag MaxHeapSize 13220
-XX:MaxHeapSize=515899392

//查看設(shè)置過值的參數(shù)
[root@localhost ~]# jinfo -flags 13220
Attaching to process ID 13220, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.211-b12
Non-default VM flags: -XX:CICompilerCount=2 -XX:InitialHeapSize=33554432 -XX:MaxHeapSize=515899392 -XX:MaxNewSize=171966464 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=11010048 -XX:OldSize=22544384 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC 
Command line: 

//查看垃圾回收器
[root@localhost ~]# jinfo -flag UseConcMarkSweepGC 13220
-XX:-UseConcMarkSweepGC
[root@localhost ~]# jinfo -flag UseG1GC 13220
-XX:-UseG1GC
[root@localhost ~]# jinfo -flag UseParallelGC 13220
-XX:+UseParallelGC

jstat查看虛擬機(jī)統(tǒng)計(jì)信息

概述

Jstat是JDK自帶的一個(gè)輕量級小工具。全稱“Java Virtual Machine statistics monitoring tool”,它位于java的bin目錄下,主要利用JVM內(nèi)建的指令對Java應(yīng)用程序的資源和性能進(jìn)行實(shí)時(shí)的命令行的監(jiān)控,包括了對Heap size和垃圾回收狀況的監(jiān)控。

jstat 用法

[root@localhost ~]# jstat -help
Usage: jstat -help|-options
       jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

option: 參數(shù)選項(xiàng)
-t: 可以在打印的列加上Timestamp列,用于顯示系統(tǒng)運(yùn)行的時(shí)間
-h: 可以在周期性數(shù)據(jù)數(shù)據(jù)的時(shí)候,可以在指定輸出多少行以后輸出一次表頭
vmid: Virtual Machine ID( 進(jìn)程的 pid)
interval: 執(zhí)行每次的間隔時(shí)間,單位為毫秒
count: 用于指定輸出多少次記錄,缺省則會(huì)一直打印

[root@localhost ~]# jstat -options
-class
-compiler
-gc
-gccapacity
-gccause
-gcmetacapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcutil
-printcompilation

option:可以從下面參數(shù)中選擇
-class 顯示ClassLoad的相關(guān)信息;
-compiler 顯示JIT編譯的相關(guān)信息;
-gc 顯示和gc相關(guān)的堆信息;
-gccapacity    顯示各個(gè)代的容量以及使用情況;
-gcmetacapacity 顯示metaspace的大??;
-gcnew 顯示新生代信息;
-gcnewcapacity 顯示新生代大小和使用情況;
-gcold 顯示老年代和永久代的信息;
-gcoldcapacity 顯示老年代的大?。?br> -gcutil   顯示垃圾收集信息;
-gccause 顯示垃圾回收的相關(guān)信息(通-gcutil),同時(shí)顯示最后一次或當(dāng)前正在發(fā)生的垃圾回收的誘因;
-printcompilation 輸出JIT編譯的方法信息;

示例一:-class

顯示加載class的數(shù)量,及所占空間等信息。

//語法:jstat -class <pid>
[root@localhost ~]# jstat -class 13220
Loaded Bytes Unloaded Bytes Time
5354 10042.1 0 0.0 5.53

Loaded : 已經(jīng)裝載的類的數(shù)量
Bytes : 裝載類所占用的字節(jié)數(shù)
Unloaded:已經(jīng)卸載類的數(shù)量
Bytes:卸載類的字節(jié)數(shù)
Time:裝載和卸載類所花費(fèi)的時(shí)間

示例二:-compiler

顯示VM實(shí)時(shí)編譯(JIT)的數(shù)量等信息。

//語法:jstat -compiler <pid>
[root@localhost ~]# jstat -compiler 13220

Compiled Failed Invalid Time FailedType FailedMethod
3035 1 0 6.72 1 org/springframework/boot/loader/jar/JarURLConnection get

Compiled:編譯任務(wù)執(zhí)行數(shù)量
Failed:編譯任務(wù)執(zhí)行失敗數(shù)量
Invalid :編譯任務(wù)執(zhí)行失效數(shù)量
Time :編譯任務(wù)消耗時(shí)間
FailedType:最后一個(gè)編譯失敗任務(wù)的類型
FailedMethod:最后一個(gè)編譯失敗任務(wù)所在的類及方法

示例三: -gc

顯示gc相關(guān)的堆信息,查看gc的次數(shù),及時(shí)間。

//語法:jstat –gc <pid>
[root@localhost ~]# jstat -gc 13220
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
6656.0 5120.0 0.0 5111.7 101376.0 72302.8 24576.0 16123.4 27776.0 27199.6 3456.0 3349.7 11 0.097 1 0.111 0.208

S0C:年輕代中第一個(gè)survivor(幸存區(qū))的容量 (字節(jié))
S1C:年輕代中第二個(gè)survivor(幸存區(qū))的容量 (字節(jié))
S0U:年輕代中第一個(gè)survivor(幸存區(qū))目前已使用空間 (字節(jié))
S1U:年輕代中第二個(gè)survivor(幸存區(qū))目前已使用空間 (字節(jié))
EC:年輕代中Eden(伊甸園)的容量 (字節(jié))
EU:年輕代中Eden(伊甸園)目前已使用空間 (字節(jié))
OC:Old代的容量 (字節(jié))
OU:Old代目前已使用空間 (字節(jié))
MC:metaspace(元空間)的容量 (字節(jié))
MU:metaspace(元空間)目前已使用空間 (字節(jié))
YGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c次數(shù)
YGCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c所用時(shí)間(s)
FGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc次數(shù)
FGCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc所用時(shí)間(s)
GCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)gc用的總時(shí)間(s)

示例四: -gccapacity

可以顯示,VM內(nèi)存中三代(young,old,perm)對象的使用和占用大小

//語法:jstat -gccapacity <pid>
[root@localhost ~]# jstat -gccapacity 13220
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
10752.0 167936. 117760.0 6656.0 5120.0 101376.0 22016.0 335872.0 24576.0 24576.0 0.0 1073152.0 27776.0 0.0 1048576.0 3456.0 11 1

NGCMN:年輕代(young)中初始化(最小)的大小(字節(jié))
NGCMX:年輕代(young)的最大容量 (字節(jié))
NGC:年輕代(young)中當(dāng)前的容量 (字節(jié))
S0C:年輕代中第一個(gè)survivor(幸存區(qū))的容量 (字節(jié))
S1C: 年輕代中第二個(gè)survivor(幸存區(qū))的容量 (字節(jié))
EC:年輕代中Eden(伊甸園)的容量 (字節(jié))
OGCMN:old代中初始化(最小)的大小 (字節(jié))
OGCMX:old代的最大容量(字節(jié))
OGC:old代當(dāng)前新生成的容量 (字節(jié))
OC:Old代的容量 (字節(jié))
MCMN:metaspace(元空間)中初始化(最小)的大小 (字節(jié))
MCMX:metaspace(元空間)的最大容量 (字節(jié))
MC:metaspace(元空間)當(dāng)前新生成的容量 (字節(jié))
CCSMN:最小壓縮類空間大小
CCSMX:最大壓縮類空間大小
CCSC:當(dāng)前壓縮類空間大小
YGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c次數(shù)
FGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc次數(shù)

示例五:-gcmetacapacity

metaspace 中對象的信息及其占用量。

//語法:jstat -gcmetacapacity <pid>
[root@localhost ~]# jstat -gcmetacapacity 13220
MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT GCT
0.0 1073152.0 27776.0 0.0 1048576.0 3456.0 11 1 0.111 0.208

MCMN:最小元數(shù)據(jù)容量
MCMX:最大元數(shù)據(jù)容量
MC:當(dāng)前元數(shù)據(jù)空間大小
CCSMN:最小壓縮類空間大小
CCSMX:最大壓縮類空間大小
CCSC:當(dāng)前壓縮類空間大小
YGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c次數(shù)
FGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc次數(shù)
FGCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc所用時(shí)間(s)
GCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)gc用的總時(shí)間(s)

示例六: -gcnew

年輕代對象的信息。

//語法:jstat -gcnew <pid>
[root@localhost ~]# jstat -gcnew 13220
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
6656.0 5120.0 0.0 5111.7 2 15 8192.0 101376.0 72302.8 11 0.097

S0C:年輕代中第一個(gè)survivor(幸存區(qū))的容量 (字節(jié))
S1C:年輕代中第二個(gè)survivor(幸存區(qū))的容量 (字節(jié))
S0U:年輕代中第一個(gè)survivor(幸存區(qū))目前已使用空間 (字節(jié))
S1U:年輕代中第二個(gè)survivor(幸存區(qū))目前已使用空間 (字節(jié))
TT:持有次數(shù)限制
MTT:最大持有次數(shù)限制
DSS:期望的幸存區(qū)大小
EC:年輕代中Eden(伊甸園)的容量 (字節(jié))
EU:年輕代中Eden(伊甸園)目前已使用空間 (字節(jié))
YGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c次數(shù)
YGCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c所用時(shí)間(s)

示例七: -gcnewcapacity

年輕代對象的信息及其占用量

//語法:jstat -gcnewcapacity <pid>
[root@localhost ~]# jstat -gcnewcapacity 13220
NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC
10752.0 167936.0 117760.0 55808.0 6656.0 55808.0 5120.0 166912.0 101376.0 11 1

NGCMN:年輕代(young)中初始化(最小)的大小(字節(jié))
NGCMX:年輕代(young)的最大容量 (字節(jié))
NGC:年輕代(young)中當(dāng)前的容量 (字節(jié))
S0CMX:年輕代中第一個(gè)survivor(幸存區(qū))的最大容量 (字節(jié))
S0C:年輕代中第一個(gè)survivor(幸存區(qū))的容量 (字節(jié))
S1CMX:年輕代中第二個(gè)survivor(幸存區(qū))的最大容量 (字節(jié))
S1C:年輕代中第二個(gè)survivor(幸存區(qū))的容量 (字節(jié))
ECMX:年輕代中Eden(伊甸園)的最大容量 (字節(jié))
EC:年輕代中Eden(伊甸園)的容量 (字節(jié))
YGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c次數(shù)
FGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc次數(shù)

示例八: -gcold

old代對象的信息

//語法:jstat -gcold <pid>
[root@localhost ~]# jstat -gcold 13220
MC MU CCSC CCSU OC OU YGC FGC FGCT GCT
27776.0 27199.6 3456.0 3349.7 24576.0 16123.4 11 1 0.111 0.208

MC :metaspace(元空間)的容量 (字節(jié))
MU:metaspace(元空間)目前已使用空間 (字節(jié))
CCSC:壓縮類空間大小
CCSU:壓縮類空間使用大小
OC:Old代的容量 (字節(jié))
OU:Old代目前已使用空間 (字節(jié))
YGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c次數(shù)
FGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc次數(shù)
FGCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc所用時(shí)間(s)
GCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)gc用的總時(shí)間(s)

示例九:-gcoldcapacity

old代對象的信息及其占用量

//語法:jstat -gcoldcapacity <pid>
[root@localhost ~]# jstat -gcoldcapacity 13220
OGCMN OGCMX OGC OC YGC FGC FGCT GCT
22016.0 335872.0 24576.0 24576.0 11 1 0.111 0.208
示例十: - gcutil

統(tǒng)計(jì)gc信息

//語法:jstat -gcutil <pid>
[root@localhost ~]# jstat -gcutil 13220
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 99.84 72.49 65.61 97.92 96.92 11 0.097 1 0.111 0.208

S0:年輕代中第一個(gè)survivor(幸存區(qū))已使用的占當(dāng)前容量百分比
S1:年輕代中第二個(gè)survivor(幸存區(qū))已使用的占當(dāng)前容量百分比
E:年輕代中Eden(伊甸園)已使用的占當(dāng)前容量百分比
O:old代已使用的占當(dāng)前容量百分比
P:perm代已使用的占當(dāng)前容量百分比
YGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c次數(shù)
YGCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c所用時(shí)間(s)
FGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc次數(shù)
FGCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc所用時(shí)間(s)
GCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)gc用的總時(shí)間(s)

示例十一:-gccause

顯示垃圾回收的相關(guān)信息(通-gcutil),同時(shí)顯示最后一次或當(dāng)前正在發(fā)生的垃圾回收的誘因。

//語法:jstat -gccause <pid>
[root@localhost ~]# jstat -gccause 13220
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
0.00 99.84 72.49 65.61 97.92 96.92 11 0.097 1 0.111 0.208 Allocation Failure No GC

S0:年輕代中第一個(gè)survivor(幸存區(qū))已使用的占當(dāng)前容量百分比
S1:年輕代中第二個(gè)survivor(幸存區(qū))已使用的占當(dāng)前容量百分比
E:年輕代中Eden(伊甸園)已使用的占當(dāng)前容量百分比
O:old代已使用的占當(dāng)前容量百分比
P:perm代已使用的占當(dāng)前容量百分比
YGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c次數(shù)

YGCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)年輕代中g(shù)c所用時(shí)間(s)
FGC:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc次數(shù)
FGCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)old代(全gc)gc所用時(shí)間(s)
GCT:從應(yīng)用程序啟動(dòng)到采樣時(shí)gc用的總時(shí)間(s)
LGCC:最后一次GC原因
GCC:當(dāng)前GC原因(No GC 為當(dāng)前沒有執(zhí)行GC)

示例十二: -printcompilation

當(dāng)前VM執(zhí)行的信息。

//語法:jstat -printcompilation <pid>
[root@localhost ~]# jstat -printcompilation 13220
Compiled Size Type Method
3071 528 1 org/apache/catalina/session/ManagerBase processExpires

Compiled :編譯任務(wù)的數(shù)目
Size :方法生成的字節(jié)碼的大小
Type:編譯類型
Method:類名和方法名用來標(biāo)識編譯的方法。類名使用/做為一個(gè)命名空間分隔符。方法名是給定類中的方法。上述格式是由-XX:+PrintComplation選項(xiàng)進(jìn)行設(shè)置的

jmap + MAT實(shí)戰(zhàn)內(nèi)存溢出

一、構(gòu)建程序溢出代碼

1. Controller

package com.ceair;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@RestController
public class MemoryController {

    private List<User> userList = new ArrayList<User>();
    private List<Class<?>> classList = new ArrayList<Class<?>>();

    /**
     * 堆內(nèi)存溢出
     * VM參數(shù):-Xms16m -Xmx16m
     * */
    @GetMapping("/heap")
    public void Test() {
        while (true) {
            int i = 0;
            userList.add(new User(++i, UUID.randomUUID().toString()));
        }
    }

    /**
     * VM參數(shù):-XX:MetaspaceSize=16M -XX:MaxMetaspaceSize=16M
     */
    @GetMapping("/nonheap")
    public void nonheap() {
        while (true) {
            classList.addAll(Metaspace.CreateClasses());
        }
    }
}

2. 實(shí)體User類

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {
    private int id;
    private String name;
}

3. Metaspace類

import java.util.ArrayList;
import java.util.List;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import static org.objectweb.asm.Opcodes.*;

/*
 * 繼承ClassLoader是為了方便調(diào)用defineClass方法,因?yàn)樵摲椒ǖ亩x為protected
 * */
public class Metaspace extends ClassLoader {
    public static List<Class<?>> CreateClasses() {
        // 類持有
        List<Class<?>> classes = new ArrayList<Class<?>>();
        // 循環(huán)1000w次生成1000w個(gè)不同的類。
        for (int i = 0; i < 10000000; ++i) {
            ClassWriter cw = new ClassWriter(0);
            // 定義一個(gè)類名稱為Class{i},它的訪問域?yàn)閜ublic,父類為java.lang.Object,不實(shí)現(xiàn)任何接口
            cw.visit(V1_1, ACC_PUBLIC, "Class" + i, null,
                    "java/lang/Object", null);
            // 定義構(gòu)造函數(shù)<init>方法
            MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>",
                    "()V", null, null);
            // 第一個(gè)指令為加載this
            mw.visitVarInsn(ALOAD, 0);
            // 第二個(gè)指令為調(diào)用父類Object的構(gòu)造函數(shù)
            mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object",
                    "<init>", "()V", false);
            // 第三條指令為return
            mw.visitInsn(RETURN);
            mw.visitMaxs(1, 1);
            mw.visitEnd();

            Metaspace test = new Metaspace();
            byte[] code = cw.toByteArray();
            // 定義類
            Class<?> exampleClass = test.defineClass("Class" + i, code, 0, code.length);
            classes.add(exampleClass);
        }
    }
}

注:記得VM參數(shù)
heap:-Xms16m -Xmx16m
nonheap:-XX:MetaspaceSize=16M -XX:MaxMetaspaceSize=16M

二、導(dǎo)出內(nèi)存映像文件

1. 內(nèi)存溢出自動(dòng)導(dǎo)出

-XX:+HeapDumpOnOutOfMemoryError  //當(dāng)發(fā)生內(nèi)存溢出的時(shí)候?qū)С?-XX:HeapDumpPath=./             //導(dǎo)出目錄

2. 使用jmap命令手動(dòng)導(dǎo)出

[root@localhost ~]# jps -l 或者 ps -ef|grep java
13220 spring-boot-test-0.0.1-SNAPSHOT.jar
54391 sun.tools.jps.Jps
[root@localhost ~]# jmap -dump:format=b,file=heap2019.hprof 13220
Dumping heap to /root/heap2019.hprof ...
Heap dump file created 
三、MAT分析內(nèi)存溢出

1. 工具下載

下載地址:https://www.eclipse.org/mat/downloads.php

//我使用的是MemoryAnalyzer-1.9.0版本。MAT不同版本按鍵位置或功能可能會(huì)有不同。

2. 將堆信息導(dǎo)入到mat中分析
File --> Open Heap Dump.. --> Leak Suspects Report --> Finish

3. 生成分析報(bào)告

具體使用參考:http://www.itdecent.cn/p/54c8e11750e4

jstack實(shí)戰(zhàn)死循環(huán)與死鎖

打印Java進(jìn)程,核心文件或遠(yuǎn)程調(diào)試服務(wù)器的Java線程堆棧跟蹤。此命令是實(shí)驗(yàn)性的,不受支持。
官網(wǎng)地址:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstack.html#BABGJDIF

死鎖問題

1. DEMO

@RestController
public class JstackDemo {

    private Object lock1 = new Object();
    private Object lock2 = new Object();

    /**
     * 死鎖
     * PS:Thread1中想要獲取的locak2已經(jīng)被 Thread2占有了
     *    Thread2中想要獲取的locak1已經(jīng)被 Thread1占有了
     */
    @GetMapping("/deadlock")
    public String read() {
        new Thread(() -> {
            synchronized (lock1) {
                try {Thread.sleep(1000);} catch (Exception e) {}
                synchronized (lock2){
                    System.out.println("Thread1 over");
                }
            }
        }).start();
        new Thread(() -> {
            synchronized (lock2) {
                try {Thread.sleep(1000);} catch (Exception e) {}
                synchronized (lock1){
                    System.out.println("Thread2 over");
                }
            }
        }).start();
        return  "deadlock";
    }
}

2. 問題排查

nohup java -jar xx.jar &

//top:找到占用CPU最大的進(jìn)程號
top -p pid -H

//控制臺輸出線程的dump信息
jstack pid

printf "%s"  //轉(zhuǎn)化成十進(jìn)制
printf "%x" //轉(zhuǎn)化成十六進(jìn)制

//或者
jstack pid > xxx.txt
sz xxx.txt

//死鎖結(jié)果如下 :
Found one Java-level deadlock:
=============================
"Thread-103":
  waiting to lock monitor 0x00007fe9d00062c8 (object 0x00000000e1ef4bc0, a java.lang.Object),
  which is held by "Thread-5"
"Thread-5":
  waiting to lock monitor 0x00007fe9dc029a58 (object 0x00000000e1ef4bb0, a java.lang.Object),
  which is held by "Thread-4"
"Thread-4":
  waiting to lock monitor 0x00007fe9d00062c8 (object 0x00000000e1ef4bc0, a java.lang.Object),
  which is held by "Thread-5"

Java stack information for the threads listed above:
===================================================
"Thread-103":
    at com.ceair.JstackDemo.lambda$read$1(JstackDemo.java:30)
    - waiting to lock <0x00000000e1ef4bc0> (a java.lang.Object)
    at com.ceair.JstackDemo$$Lambda$390/489447259.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:748)
"Thread-5":
    at com.ceair.JstackDemo.lambda$read$1(JstackDemo.java:32)
    - waiting to lock <0x00000000e1ef4bb0> (a java.lang.Object)
    - locked <0x00000000e1ef4bc0> (a java.lang.Object)
    at com.ceair.JstackDemo$$Lambda$390/489447259.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:748)
"Thread-4":
    at com.ceair.JstackDemo.lambda$read$0(JstackDemo.java:24)
    - waiting to lock <0x00000000e1ef4bc0> (a java.lang.Object)
    - locked <0x00000000e1ef4bb0> (a java.lang.Object)
    at com.ceair.JstackDemo$$Lambda$389/559309503.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.
死循環(huán)CPU飆高

1. DEMO


    /**
     * 死循環(huán)
     * */
    @GetMapping("/loop")
    public List<Long> loop(){
        String data = "{\"data\":[{\"partnerid\":]";
        return getPartneridsFromJson(data);
    }

    public static List<Long> getPartneridsFromJson(String data){
        //{\"data\":[{\"partnerid\":982,\"count\":\"10000\",\"cityid\":\"11\"},{\"partnerid\":983,\"count\":\"10000\",\"cityid\":\"11\"},{\"partnerid\":984,\"count\":\"10000\",\"cityid\":\"11\"}]}
        //上面是正常的數(shù)據(jù)
        List<Long> list = new ArrayList<Long>(2);
        if(data == null || data.length() <= 0){
            return list;
        }
        int datapos = data.indexOf("data");
        if(datapos < 0){
            return list;
        }
        int leftBracket = data.indexOf("[",datapos);
        int rightBracket= data.indexOf("]",datapos);
        if(leftBracket < 0 || rightBracket < 0){
            return list;
        }
        String partners = data.substring(leftBracket+1,rightBracket);
        if(partners == null || partners.length() <= 0){
            return list;
        }
        while(partners!=null && partners.length() > 0){
            int idpos = partners.indexOf("partnerid");
            if(idpos < 0){
                break;
            }
            int colonpos = partners.indexOf(":",idpos);
            int commapos = partners.indexOf(",",idpos);
            if(colonpos < 0 || commapos < 0){
                //partners = partners.substring(idpos+"partnerid".length());//1
                continue;
            }
            String pid = partners.substring(colonpos+1,commapos);
            if(pid == null || pid.length() <= 0){
                //partners = partners.substring(idpos+"partnerid".length());//2
                continue;
            }
            try{
                list.add(Long.parseLong(pid));
            }catch(Exception e){
                //do nothing
            }
            partners = partners.substring(commapos);
        }
        return list;
    }

2. 問題排查

//啟動(dòng)項(xiàng)目
nohup java -jar xx.jar &

//找到占用CPU最大的進(jìn)程號
top

//查看具體進(jìn)程線程信息
top -p pid -H
47174 root      20   0 3029452 241332   4836 R 32.3 12.0   0:29.69 java
47175 root      20   0 3029452 241332   4836 R 32.3 12.0   0:23.61 java
47179 root      20   0 3029452 241332   4836 R 32.0 12.0   0:09.66 java
47178 root      20   0 3029452 241332   4836 R 25.3 12.0   0:10.71 java
47180 root      20   0 3029452 241332   4836 R 25.3 12.0   0:08.56 java
47173 root      20   0 3029452 241332   4836 R 25.0 12.0   0:29.51 java
47177 root      20   0 3029452 241332   4836 R 25.0 12.0   0:10.14 java

//轉(zhuǎn)化成十六進(jìn)制
printf "%x" 47174
//printf "%s"  //轉(zhuǎn)化成十進(jìn)制
//printf "%x" //轉(zhuǎn)化成十六進(jìn)制

//控制臺輸出線程的dump信息
jstack pid
//或者下載到本地
jstack pid > xxx.txt
sz xxx.txt

"http-nio-8088-exec-2" #16 daemon prio=5 os_prio=0 tid=0x00007fa2e51af000 nid=0xb846 runnable [0x00007fa2b49ec000]
   java.lang.Thread.State: RUNNABLE
    at java.lang.String.indexOf(String.java:1769)
    at java.lang.String.indexOf(String.java:1718)
    at com.ceair.JstackDemo.getPartneridsFromJson(JstackDemo.java:77)
    at com.ceair.JstackDemo.loop(JstackDemo.java:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    - locked <0x00000000e1cea108> (a org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容