JVM性能調(diào)優(yōu)指南(一)

1、JVM的參數(shù)類型

1.1 標準參數(shù):在各jdk版本中較穩(wěn)定

-help
-server -client
-version -showversion
-cp -classpath

1.2 X參數(shù)

1.2.1非標準化參數(shù)
1.2.2 -Xint:完全解釋執(zhí)行

調(diào)整為完全解釋執(zhí)行編譯模式:

MacBook-Pro:dubbo-learn chuanzhou$ java -Xint -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, interpreted mode)
1.2.3 -Xcomp:第一次使用就編譯成本地代碼

調(diào)整為編譯執(zhí)行編譯模式:

MacBook-Pro:dubbo-learn chuanzhou$ java -Xcomp -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, compiled mode)
1.2.4 -Xmixed:混合模式,JVM自己來決定是否編譯成本地代碼
MacBook-Pro:~ chuanzhou$ java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

最后一行的mixed mode表明JVM默認使用的編譯模式是混合模式

1.3 XX參數(shù)

使用最多的一種參數(shù)類型

1.3.1 Boolean類型

格式:-XX:[+/-] <name> 表示啟用或者禁用name屬性
比如:
-XX:+UseConcMarkSweepGC 表示啟用CMS垃圾回收器
-XX:+UseG1GC 表示啟用G1垃圾回收器

1.3.2 非Boolean類型

格式:-XX:<name> = <value> 表示name屬性的值為value
比如:
-XX:MaxGCPauseMillis=500 表示GC最大停頓時間是500毫秒
-XX:GCTimeRatio=19 表示...

1.3.3 -Xmx -Xms

雖然1以X開頭,但是不是X類型參數(shù),而是XX類型的參數(shù)

  • -Xmx等價于-XX:MaxHeapSize 表示最大堆內(nèi)存大小,可使用jinfo -flag MaxHeapSize 進程id查看,如下:
[root@izwz93osmk5vi5qwqyscxaz bin]# ps -ef|grep java
root      9723     1  0 4月24 ?       04:28:59 /usr/program/jdk1.8.0_72/jre/bin/java -Djava.util.logging.config.file=/opt/tomcat/apache-tomcat-8.0.50/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dignore.endorsed.dirs= -classpath /opt/tomcat/apache-tomcat-8.0.50/bin/bootstrap.jar:/opt/tomcat/apache-tomcat-8.0.50/bin/tomcat-juli.jar -Dcatalina.base=/opt/tomcat/apache-tomcat-8.0.50 -Dcatalina.home=/opt/tomcat/apache-tomcat-8.0.50 -Djava.io.tmpdir=/opt/tomcat/apache-tomcat-8.0.50/temp org.apache.catalina.startup.Bootstrap start
root     20037 19984  0 20:53 pts/2    00:00:00 grep --color=auto java
[root@izwz93osmk5vi5qwqyscxaz bin]# ./jinfo -flag MaxHeapSize 9723
-XX:MaxHeapSize=482344960
[root@izwz93osmk5vi5qwqyscxaz bin]#
  • -Xms等價于-XX:InitalHeapSize 表示堆內(nèi)存初始大小

  • -Xss等價于-XX:InitalStackSize 表示線程棧的初始大小,可以使用jinfo -flag ThreadStackSize 進程id查看,如下:

[root@izwz93osmk5vi5qwqyscxaz bin]# ps -ef
[root@izwz93osmk5vi5qwqyscxaz bin]# ps -ef|grep java
root      9723     1  0 4月24 ?       04:28:59 /usr/program/jdk1.8.0_72/jre/bin/java -Djava.util.logging.config.file=/opt/tomcat/apache-tomcat-8.0.50/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dignore.endorsed.dirs= -classpath /opt/tomcat/apache-tomcat-8.0.50/bin/bootstrap.jar:/opt/tomcat/apache-tomcat-8.0.50/bin/tomcat-juli.jar -Dcatalina.base=/opt/tomcat/apache-tomcat-8.0.50 -Dcatalina.home=/opt/tomcat/apache-tomcat-8.0.50 -Djava.io.tmpdir=/opt/tomcat/apache-tomcat-8.0.50/temp org.apache.catalina.startup.Bootstrap start
root     20037 19984  0 20:53 pts/2    00:00:00 grep --color=auto java
[root@izwz93osmk5vi5qwqyscxaz bin]# ./jinfo -flag MaxHeapSize 9723
-XX:MaxHeapSize=482344960
[root@izwz93osmk5vi5qwqyscxaz bin]# ./jinfo -flag ThreadStackSize 9723
-XX:ThreadStackSize=1024
[root@izwz93osmk5vi5qwqyscxaz bin]#

2、JVM運行時參數(shù)查看

  • -XX:+printFlagsInitial 查看JVM運行時初始值
  • -XX:+printFlagsFinal 查看JVM運行時最終值
  • -XX:+UnlockExperimentalVMOptions 解鎖實驗參數(shù)
  • -XX:+UnlockDiagnosticVMOptions 解鎖診斷參數(shù)
  • -XX:+PrintCommandLineFlags 打印命令行參數(shù)

如查看JVM版本信息:java -XX:+PrintFlagsFinal -version > ~/version.txt

version.txt中部分參數(shù):
[Global flags]
    uintx AdaptiveSizeDecrementScaleFactor          = 4                                   {product}
    uintx AdaptiveSizeMajorGCDecayTimeScale         = 10                                  {product}
    uintx AdaptiveSizePausePolicy                   = 0                                   {product}
    uintx AdaptiveSizePolicyCollectionCostMargin    = 50                                  {product}
    uintx AdaptiveSizePolicyInitializingSteps       = 20                                  {product}
    uintx AdaptiveSizePolicyOutputInterval          = 0                                   {product}
    uintx AdaptiveSizePolicyWeight                  = 10                                  {product}
    uintx AdaptiveSizeThroughPutPolicy              = 0                                   {product}
    uintx AdaptiveTimeWeight                        = 25                                  {product}
     bool AdjustConcurrency                         = false                               {product}
     bool AggressiveOpts                            = false                               {product}
     bool C1ProfileVirtualCalls                     = true                                {C1 product}
     bool C1UpdateMethodData                        = true                                {C1 product}
     intx CICompilerCount                          := 2                                   {product}
     bool CICompilerCountPerCPU                     = true                                {product}
     bool CITime                                    = false                               {product}
     bool CMSAbortSemantics                         = false                               {product}
    uintx CMSAbortablePrecleanMinWorkPerIteration   = 100                                 {product}
     intx CMSAbortablePrecleanWaitMillis            = 100                                 {manageable}
    uintx CMSBitMapYieldQuantum                     = 10485760

注:=表示默認值,=:表示修改后的值

jps:查看Java進程

[root@izwz93osmk5vi5qwqyscxaz bin]# ./jps
20160 Jps
9723 Bootstrap
[root@izwz93osmk5vi5qwqyscxaz bin]# ./jps -l
20170 sun.tools.jps.Jps
9723 org.apache.catalina.startup.Bootstrap
[root@izwz93osmk5vi5qwqyscxaz bin]#

關于jps等命令的詳解,可參考此文檔https://docs.oracle.com/javase/8/docs/technotes/tools/unix/index.html

jinfo:查看指定Java進程運行時參數(shù)

如查看一個java進程id為9723的tomcat服務最大堆內(nèi)存大小

[root@izwz93osmk5vi5qwqyscxaz bin]# ps -ef|grep java
root      9723     1  0 4月24 ?       04:29:03 /usr/program/jdk1.8.0_72/jre/bin/java -Djava.util.logging.config.file=/opt/tomcat/apache-tomcat-8.0.50/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dignore.endorsed.dirs= -classpath /opt/tomcat/apache-tomcat-8.0.50/bin/bootstrap.jar:/opt/tomcat/apache-tomcat-8.0.50/bin/tomcat-juli.jar -Dcatalina.base=/opt/tomcat/apache-tomcat-8.0.50 -Dcatalina.home=/opt/tomcat/apache-tomcat-8.0.50 -Djava.io.tmpdir=/opt/tomcat/apache-tomcat-8.0.50/temp org.apache.catalina.startup.Bootstrap start
root     20187 20123  0 21:34 pts/2    00:00:00 grep --color=auto java
[root@izwz93osmk5vi5qwqyscxaz bin]# ./jinfo -flag MaxHeapSize 9723
-XX:MaxHeapSize=482344960
[root@izwz93osmk5vi5qwqyscxaz bin]#

查看一個進程的所有運行時參數(shù):

[root@izwz93osmk5vi5qwqyscxaz bin]# ./jinfo -flags 9732
Attaching to process ID 9732, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.72-b15
Non-default VM flags: -XX:CICompilerCount=2 
-XX:InitialHeapSize=31457280 -XX:MaxHeapSize=482344960 
-XX:MaxNewSize=160759808 -XX:MinHeapDeltaBytes=196608 
-XX:NewSize=10485760 -XX:OldSize=20971520 
-XX:+UseCompressedClassPointers -XX:+UseCompressedOops
Command line:  -Djava.util.logging.config.file=/opt/tomcat/apache-tomcat-8.0.50/conf/logging.properties 
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 
-Djava.protocol.handler.pkgs=org.apache.catalina.webresources 
-Dignore.endorsed.dirs= -Dcatalina.base=/opt/tomcat/apache-tomcat-8.0.50 
-Dcatalina.home=/opt/tomcat/apache-tomcat-8.0.50 
-Djava.io.tmpdir=/opt/tomcat/apache-tomcat-8.0.50/temp
[root@izwz93osmk5vi5qwqyscxaz bin]#

Non-default VM flags表示手動賦值過的參數(shù),其中有些是tomcat設置的
Command line:與Non-default VM flags

查看垃圾回收器信息

MacBook-Pro:dubbo-learn chuanzhou$ jinfo -flag UseConcMarkSweepGc 29159
no such flag 'UseConcMarkSweepGc'
MacBook-Pro:dubbo-learn chuanzhou$ jinfo -flag UseG1Gc 29159
no such flag 'UseG1Gc'
MacBook-Pro:dubbo-learn chuanzhou$ jinfo -flag UseParallelGc 29159
no such flag 'UseParallelGc'

3、jstat查看虛擬機統(tǒng)計信息

3.1 類裝載

格式:jstat -class 進程id 每隔多少毫秒 一共輸出多少次
如:查看一個進程id為29159的java進程,每隔1s輸出,一共輸出10次

MacBook-Pro:dubbo-learn chuanzhou$ jstat -class 29159 1000 10
Loaded  Bytes  Unloaded  Bytes     Time
  3204  6088.2        0     0.0       2.14
  3204  6088.2        0     0.0       2.14
  3204  6088.2        0     0.0       2.14
  3204  6088.2        0     0.0       2.14
  3204  6088.2        0     0.0       2.14
  3204  6088.2        0     0.0       2.14
  3204  6088.2        0     0.0       2.14
  3204  6088.2        0     0.0       2.14
  3204  6088.2        0     0.0       2.14
  3204  6088.2        0     0.0       2.14
  • Loaded:表示類加載的個數(shù)
  • Bytes:表示類加載的大小,單位為kb
  • UnLoaded:表示類卸載的個數(shù)
  • Bytes:表示類卸載的大小,單位為kb
  • Time:表示類加載和卸載的時間

3.2 垃圾收集

要查看一個java進程的垃圾收集器信息,可使用jstat -gc 進程id 每隔多少毫秒 一共輸出多少次

MacBook-Pro:dubbo-learn chuanzhou$ jstat -gc 29159 1000 3
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
5120.0 5120.0 4308.8  0.0   33280.0  17845.6   87552.0      88.0    18944.0 18304.7 2304.0 2144.9      2    0.014   0      0.000    0.014
5120.0 5120.0 4308.8  0.0   33280.0  17845.6   87552.0      88.0    18944.0 18304.7 2304.0 2144.9      2    0.014   0      0.000    0.014
5120.0 5120.0 4308.8  0.0   33280.0  17845.6   87552.0      88.0    18944.0 18304.7 2304.0 2144.9      2    0.014   0      0.000    0.014

S0C: Current survivor space 0 capacity (kB).表示survivor 0區(qū)的總大小
S1C: Current survivor space 1 capacity (kB).表示survivor 1區(qū)的總大小
S0U: Survivor space 0 utilization (kB).表示survivor 0區(qū)使用了的大小
S1U: Survivor space 1 utilization (kB).表示survivor 1區(qū)使用了的大小
EC: Current eden space capacity (kB).表示eden區(qū)總大小
EU: Eden space utilization (kB).表示eden區(qū)使用了的大小
OC: Current old space capacity (kB).表示old區(qū)總大小
OU: Old space utilization (kB).表示old區(qū)使用了的大小
MC: Metaspace capacity (kB).表示Metaspace區(qū)總大小
MU: Metacspace utilization (kB).表示Metaspace區(qū)使用了的大小
CCSC: Compressed class space capacity (kB).表示壓縮類空間總量
CCSU: Compressed class space used (kB).表示壓縮類空間使用量
YGC: Number of young generation garbage collection events.表示Young GC的次數(shù)
YGCT: Young generation garbage collection time.表示Young GC的時間
FGC: Number of full GC events.表示full GC的次數(shù)
FGCT: Full garbage collection time.表示full GC的時間
GCT: Total garbage collection time.表示總的 GC的時間

3.3 JIT編譯

3.3.1 -compiler參數(shù)
MacBook-Pro:dubbo-learn chuanzhou$ jstat -compiler 29159 1000 5
Compiled Failed Invalid   Time   FailedType FailedMethod
    1284      0       0     3.50          0
    1284      0       0     3.50          0
    1284      0       0     3.50          0
    1284      0       0     3.50          0
    1284      0       0     3.50          0
  • Compiled:表示編譯成功的方法數(shù)量
  • Failed:表示編譯失敗的方法數(shù)量
  • Invalid:表示編譯無效的方法數(shù)量
  • Time:編譯所花費的時間
  • FailedType:編譯失敗類型
  • FailedMethod:編譯失敗方法
3.3.2 -printcompilation參數(shù)

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

模擬內(nèi)存溢出:

@RestController
public class MemoryController {
    
    private List<User>  userList = new ArrayList<User>();
    private List<Class<?>>  classList = new ArrayList<Class<?>>();
    
    /**
     * -Xmx32M -Xms32M
     * */
    @GetMapping("/heap")
    public String heap() {
        int i=0;
        while(true) {
            userList.add(new User(i++, UUID.randomUUID().toString()));
        }
    }
    
    
    /**
     * -XX:MetaspaceSize=32M -XX:MaxMetaspaceSize=32M
     * */
    @GetMapping("/nonheap")
    public String nonheap() {
        while(true) {
            classList.addAll(Metaspace.createClasses());
        }
    }
    
}

package com.imooc.monitor_tuning.chapter2;
import java.util.ArrayList;
import java.util.List;

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

/*
 * https://blog.csdn.net/bolg_hero/article/details/78189621
 * 繼承ClassLoader是為了方便調(diào)用defineClass方法,因為該方法的定義為protected
 * */
public class Metaspace extends ClassLoader {
    
    public static List<Class<?>> createClasses() {
        // 類持有
        List<Class<?>> classes = new ArrayList<Class<?>>();
        // 循環(huán)1000w次生成1000w個不同的類。
        for (int i = 0; i < 10000000; ++i) {
            ClassWriter cw = new ClassWriter(0);
            // 定義一個類名稱為Class{i},它的訪問域為public,父類為java.lang.Object,不實現(xiàn)任何接口
            cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "Class" + i, null,
                    "java/lang/Object", null);
            // 定義構(gòu)造函數(shù)<init>方法
            MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
                    "()V", null, null);
            // 第一個指令為加載this
            mw.visitVarInsn(Opcodes.ALOAD, 0);
            // 第二個指令為調(diào)用父類Object的構(gòu)造函數(shù)
            mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object",
                    "<init>", "()V");
            // 第三條指令為return
            mw.visitInsn(Opcodes.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);
        }
        return classes;
    }
}
package com.imooc.monitor_tuning.chapter2;

public class User {
    private int id;
    private String name;
    public User(int id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
}

設置啟動參數(shù):


啟動參數(shù)

啟動application,發(fā)現(xiàn)出現(xiàn)內(nèi)存溢出

4.1 如何導出內(nèi)存溢出映像文件

4.2 內(nèi)存溢出自動導出

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./

4.3 使用jmap命令手動導出

格式:jmap -dump:format=b,file=路徑/heap.hprof 進程id
其他命令:jmap -heap 進程id 查看堆信息

[root@izwz93osmk5vi5qwqyscxaz bin]# ./jmap -heap 9723
Attaching to process ID 9723, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.72-b15

using thread-local object allocation.
Mark Sweep Compact GC

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 482344960 (460.0MB)
   NewSize                  = 10485760 (10.0MB)
   MaxNewSize               = 160759808 (153.3125MB)
   OldSize                  = 20971520 (20.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 32178176 (30.6875MB)
   used     = 16081160 (15.336189270019531MB)
   free     = 16097016 (15.351310729980469MB)
   49.97536218336303% used
Eden Space:
   capacity = 28639232 (27.3125MB)
   used     = 16054760 (15.311012268066406MB)
   free     = 12584472 (12.001487731933594MB)
   56.058626153103546% used
From Space:
   capacity = 3538944 (3.375MB)
   used     = 26400 (0.025177001953125MB)
   free     = 3512544 (3.349822998046875MB)
   0.7459852430555556% used
To Space:
   capacity = 3538944 (3.375MB)
   used     = 0 (0.0MB)
   free     = 3538944 (3.375MB)
   0.0% used
tenured generation:
   capacity = 71221248 (67.921875MB)
   used     = 57115304 (54.469398498535156MB)
   free     = 14105944 (13.452476501464844MB)
   80.19419148622613% used

27532 interned Strings occupying 3194040 bytes.
4.4 使用MAT分析映像文件
MAT分析
  • Class Name:類名
  • Objects:對象數(shù)量
  • Shallow Heap:
  • Retained Heap:占用的內(nèi)存大小

右鍵查看com.imooc.monitor_tuning.chapter2.User的強引用


image.png
image.png

也可以查看對象樹:


對象樹

5、jstack實戰(zhàn)死循環(huán)與死鎖

格式:jstack 進程id

2018-09-05 07:59:21
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.72-b15 mixed mode):

"Attach Listener" #16 daemon prio=9 os_prio=0 tid=0x00007f3d9c001000 nid=0x521f waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"localhost-startStop-1" #15 daemon prio=5 os_prio=0 tid=0x00007f3dac002800 nid=0x5208 runnable [0x00007f3da15d1000]
   java.lang.Thread.State: RUNNABLE
    at java.io.FileInputStream.readBytes(Native Method)
    at java.io.FileInputStream.read(FileInputStream.java:255)
    at sun.security.provider.SeedGenerator$URLSeedGenerator.getSeedBytes(SeedGenerator.java:539)
    at sun.security.provider.SeedGenerator.generateSeed(SeedGenerator.java:144)
    at sun.security.provider.SecureRandom$SeederHolder.<clinit>(SecureRandom.java:203)
    at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:221)
    - locked <0x00000000e3e90be0> (a sun.security.provider.SecureRandom)
    at java.security.SecureRandom.nextBytes(SecureRandom.java:468)
    - locked <0x00000000e3e910c0> (a java.security.SecureRandom)
    at java.security.SecureRandom.next(SecureRandom.java:491)
    at java.util.Random.nextInt(Random.java:329)
    at org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom(SessionIdGeneratorBase.java:240)
    at org.apache.catalina.util.SessionIdGeneratorBase.getRandomBytes(SessionIdGeneratorBase.java:174)
    at org.apache.catalina.util.StandardSessionIdGenerator.generateSessionId(StandardSessionIdGenerator.java:34)
    at org.apache.catalina.util.SessionIdGeneratorBase.generateSessionId(SessionIdGeneratorBase.java:167)
    at org.apache.catalina.util.SessionIdGeneratorBase.startInternal(SessionIdGeneratorBase.java:260)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    - locked <0x00000000e3e90730> (a org.apache.catalina.util.StandardSessionIdGenerator)
    at org.apache.catalina.session.ManagerBase.startInternal(ManagerBase.java:717)
    at org.apache.catalina.session.StandardManager.startInternal(StandardManager.java:352)
    - locked <0x00000000e42eefb0> (a org.apache.catalina.session.StandardManager)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    - locked <0x00000000e42eefb0> (a org.apache.catalina.session.StandardManager)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5339)
    - locked <0x00000000ed3c6ca0> (a org.apache.catalina.core.StandardContext)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    - locked <0x00000000ed3c6ca0> (a org.apache.catalina.core.StandardContext)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:753)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:729)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:974)
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1850)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

"Catalina-startStop-1" #14 daemon prio=5 os_prio=0 tid=0x00007f3dc4437000 nid=0x5207 waiting on condition [0x00007f3da16d2000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000ed3c6fc0> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429)
    at java.util.concurrent.FutureTask.get(FutureTask.java:191)
    at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:766)
    at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:436)
    at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1580)
    at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:322)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:95)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:388)
    - locked <0x00000000ed03ec38> (a org.apache.catalina.core.StandardHost)
    at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:333)
    - locked <0x00000000ed03ec38> (a org.apache.catalina.core.StandardHost)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:960)
    - locked <0x00000000ed03ec38> (a org.apache.catalina.core.StandardHost)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:871)
    - locked <0x00000000ed03ec38> (a org.apache.catalina.core.StandardHost)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    - locked <0x00000000ed03ec38> (a org.apache.catalina.core.StandardHost)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

"NioBlockingSelector.BlockPoller-2" #13 daemon prio=5 os_prio=0 tid=0x00007f3dc4429800 nid=0x5206 runnable [0x00007f3da17d4000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
    at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
    at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    - locked <0x00000000ed3c75a8> (a sun.nio.ch.Util$2)
    - locked <0x00000000ed3c75b8> (a java.util.Collections$UnmodifiableSet)
    - locked <0x00000000ed3c7560> (a sun.nio.ch.EPollSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    at org.apache.tomcat.util.net.NioBlockingSelector$BlockPoller.run(NioBlockingSelector.java:301)

"NioBlockingSelector.BlockPoller-1" #12 daemon prio=5 os_prio=0 tid=0x00007f3dc440e800 nid=0x5205 runnable [0x00007f3da18d5000]
   java.lang.Thread.State: RUNNABLE
    at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
    at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
    at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
    at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
    - locked <0x00000000ed3c77e0> (a sun.nio.ch.Util$2)
    - locked <0x00000000ed3c77f0> (a java.util.Collections$UnmodifiableSet)
    - locked <0x00000000ed3c7798> (a sun.nio.ch.EPollSelectorImpl)
    at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
    at org.apache.tomcat.util.net.NioBlockingSelector$BlockPoller.run(NioBlockingSelector.java:301)

"GC Daemon" #11 daemon prio=2 os_prio=0 tid=0x00007f3dc4356800 nid=0x5204 in Object.wait() [0x00007f3dc81a0000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000ed0d57f0> (a sun.misc.GC$LatencyLock)
    at sun.misc.GC$Daemon.run(GC.java:117)
    - locked <0x00000000ed0d57f0> (a sun.misc.GC$LatencyLock)

"AsyncFileHandlerWriter-789451787" #10 daemon prio=5 os_prio=0 tid=0x00007f3dc4105000 nid=0x5203 waiting on condition [0x00007f3dc8338000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000ecec1210> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
    at java.util.concurrent.LinkedBlockingDeque.pollFirst(LinkedBlockingDeque.java:522)
    at java.util.concurrent.LinkedBlockingDeque.poll(LinkedBlockingDeque.java:684)
    at org.apache.juli.AsyncFileHandler$LoggerThread.run(AsyncFileHandler.java:153)

"Service Thread" #7 daemon prio=9 os_prio=0 tid=0x00007f3dc40b3800 nid=0x5201 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f3dc40b0800 nid=0x5200 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f3dc40ae800 nid=0x51ff waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f3dc40ad000 nid=0x51fe runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f3dc407a000 nid=0x51fd in Object.wait() [0x00007f3dc893e000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000ecec2320> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x00000000ecec2320> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f3dc4075000 nid=0x51fc in Object.wait() [0x00007f3dc8a3f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000ecec24d8> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x00000000ecec24d8> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 prio=5 os_prio=0 tid=0x00007f3dc4009000 nid=0x51fa waiting on condition [0x00007f3dcc417000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000ed3c7340> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429)
    at java.util.concurrent.FutureTask.get(FutureTask.java:191)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:943)
    - locked <0x00000000ecfb7038> (a org.apache.catalina.core.StandardEngine)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
    - locked <0x00000000ecfb7038> (a org.apache.catalina.core.StandardEngine)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    - locked <0x00000000ecfb7038> (a org.apache.catalina.core.StandardEngine)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:441)
    - locked <0x00000000ecfb7038> (a org.apache.catalina.core.StandardEngine)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    - locked <0x00000000ecfa2330> (a org.apache.catalina.core.StandardService)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:789)
    - locked <0x00000000ecf4e258> (a java.lang.Object)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    - locked <0x00000000ecf1c578> (a org.apache.catalina.core.StandardServer)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:641)
    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.apache.catalina.startup.Bootstrap.start(Bootstrap.java:349)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:483)

"VM Thread" os_prio=0 tid=0x00007f3dc406d800 nid=0x51fb runnable

"VM Periodic Task Thread" os_prio=0 tid=0x00007f3dc40b7000 nid=0x5202 waiting on condition

JNI global references: 59
  • localhost-startStop-1:線程名
  • daemon:后臺線程
  • prio:優(yōu)先級
  • os_prio:系統(tǒng)優(yōu)先級
  • tid:線程id
  • nid:操作系統(tǒng)id
  • java.lang.Thread.State:線程狀態(tài);NEW-線程尚未啟動, RUNNABLE- 線程運行中,BLOCKED-等待一個鎖, WAITINH-等待另一個線程, TIMED_WAITING-限時等待另一個線程, TERMINATED-已退出
5.1 實戰(zhàn)死循環(huán)
import java.util.ArrayList;
import java.util.List;

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

@RestController
public class CpuController {
    
    /**
     * 死循環(huán)
     * */
    @RequestMapping("/loop")
    public List<Long> loop(){
        String data = "{\"data\":[{\"partnerid\":]";
        return getPartneridsFromJson(data);
    }
    
    private Object lock1 = new Object();
    private Object lock2 = new Object();
    
    /**
     * 死鎖
     * */
    @RequestMapping("/deadlock")
    public String deadlock(){
        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";
    }
    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;  
    }  
    
}

訪問/loop端點三次,然后使用top命令:


#導出線程堆棧
$ jstack 7930 > 7930.txt
#打印該進程下的線程
$ top -p 7930 -H
#將十進制線程id轉(zhuǎn)換為16進制
$ printf "%x" 8247
2037

然后在導出的7930.txt文件中找到2037


死循環(huán)

訪問/loop端點,制造死循環(huán),使用jstack命令導出線程堆棧信息:


死鎖

最后一行已提示:Found 1 deadlock

相關資料:
jdk8工具集
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/index.html
Troubleshooting
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/
jps
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jps.html
jinfo
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jinfo.html
jstat
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html
jmap:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jmap.html
mat:
http://www.eclipse.org/mat/downloads.php
jstack:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstack.html
java線程的狀態(tài)
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr034.html
java線程狀態(tài)轉(zhuǎn)化:
https://mp.weixin.qq.com/s/GsxeFM7QWuR--Kbpb7At2w
死循環(huán)導致CPU負載高
https://blog.csdn.net/goldenfish1919/article/details/8755378
正則表達式導致死循環(huán):
https://blog.csdn.net/goldenfish1919/article/details/49123787

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

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