jvm监控与调优之jdk命令行工具

jvm监控与调优之jdk命令行工具

目录


jvm的参数类型

标准参数
  • -help
  • -server -client
  • -version -showversion
  • -cp -classpath
X参数
  • 非标准化参数(在各个JDK版本中可能会变,但是变动比较小)
  • -Xint : 解释执行
//使用命令:java -Xint -version  jvm为interpreted mode(解释执行)
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 : 编译执行 第一次使用就编译成本地代码
//使用命令:java -Xcomp -version  jvm为compiled mode(编译执行)
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参数
  • 非标转化参数
  • 相对不稳定
  • 主要用于JVM调优和Debug
  • 参数分类
    • Boolean 类型
      //格式:-XX:[+-]<name> 表示启用或禁用name属性
      //比如:
          -XX:+UseConcMarkSweepGC  //表示启用CMS垃圾收集器([+]号代表启用,[-]代表禁用)
          -XX:+UseGcG1        //表示启用G1垃圾收集器
      
    • 非 Boolean 类型
      //格式:-XX:<name>=<value> 表示name属性的值是value
      //比如:
          -XX:MaxGcPauseMillis=500 //GC的最大停顿时间是500毫秒
          -XX:GCTimeRatio=19    //设置吞吐量大小,它的值是一个 0-100 之间的整数。假设 GCTimeRatio 的值为 n,那么系统将花费不超过 1/(1+n) 的时间用于垃圾收集
      
-Xmx -Xms
  • 不是X参数,而是XX参数
  • -Xms 等价于 -XX:InitialHeapSize 初始化的堆大小
  • -Xmx 等价于 -XX:MaxHeapSize 最大化的堆大小
  • jinfo -flag MaxHeapSize <进程编号>
    //查询所有java进程
    [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   //运行时最大的堆大小
    
  • jinfo -flag ThreadStackSize <进程编号>
    [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   //启动一个线程需要的内存大小
    

运行时jvm参数查看

运行时参数
  • -XX:+PrintFlagsInitial
  • -XX:PrintFlagsFinal
  • -XX:+UnlockExperimentalVMOptions 解锁实验参数
  • -XX:+UnlockDiagnosticVMOptions 解锁诊断参数
  • -XX:+PrintCommandLineFlags 打印命令行参数
//=表示默认值
//:被用户或者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进程,参考网站: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自带的命令,可以用来查看正在运行的Java应用程序的扩展参数,甚至支持在运行时,修改部分参数。

官网地址:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jinfo.html#BCGEBFDD

//查看最大内存
[root@localhost ~]# jinfo -flag MaxHeapSize 13220
-XX:MaxHeapSize=515899392

//查看设置过值的参数
[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查看虚拟机统计信息

概述

Jstat是JDK自带的一个轻量级小工具。全称“Java Virtual Machine statistics monitoring tool”,它位于java的bin目录下,主要利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和垃圾回收状况的监控。

jstat 用法

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

option: 参数选项
-t: 可以在打印的列加上Timestamp列,用于显示系统运行的时间
-h: 可以在周期性数据数据的时候,可以在指定输出多少行以后输出一次表头
vmid: Virtual Machine ID( 进程的 pid)
interval: 执行每次的间隔时间,单位为毫秒
count: 用于指定输出多少次记录,缺省则会一直打印

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

option:可以从下面参数中选择
-class 显示ClassLoad的相关信息;
-compiler 显示JIT编译的相关信息;
-gc 显示和gc相关的堆信息;
-gccapacity    显示各个代的容量以及使用情况;
-gcmetacapacity 显示metaspace的大小;
-gcnew 显示新生代信息;
-gcnewcapacity 显示新生代大小和使用情况;
-gcold 显示老年代和永久代的信息;
-gcoldcapacity 显示老年代的大小;
-gcutil   显示垃圾收集信息;
-gccause 显示垃圾回收的相关信息(通-gcutil),同时显示最后一次或当前正在发生的垃圾回收的诱因;
-printcompilation 输出JIT编译的方法信息;

示例一:-class

显示加载class的数量,及所占空间等信息。

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

Loaded : 已经装载的类的数量
Bytes : 装载类所占用的字节数
Unloaded:已经卸载类的数量
Bytes:卸载类的字节数
Time:装载和卸载类所花费的时间

示例二:-compiler

显示VM实时编译(JIT)的数量等信息。

//语法: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:编译任务执行数量
Failed:编译任务执行失败数量
Invalid :编译任务执行失效数量
Time :编译任务消耗时间
FailedType:最后一个编译失败任务的类型
FailedMethod:最后一个编译失败任务所在的类及方法

示例三: -gc

显示gc相关的堆信息,查看gc的次数,及时间。

//语法: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:年轻代中第一个survivor(幸存区)的容量 (字节)
S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
EC:年轻代中Eden(伊甸园)的容量 (字节)
EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
OC:Old代的容量 (字节)
OU:Old代目前已使用空间 (字节)
MC:metaspace(元空间)的容量 (字节)
MU:metaspace(元空间)目前已使用空间 (字节)
YGC:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)

示例四: -gccapacity

可以显示,VM内存中三代(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)中初始化(最小)的大小(字节)
NGCMX:年轻代(young)的最大容量 (字节)
NGC:年轻代(young)中当前的容量 (字节)
S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
S1C: 年轻代中第二个survivor(幸存区)的容量 (字节)
EC:年轻代中Eden(伊甸园)的容量 (字节)
OGCMN:old代中初始化(最小)的大小 (字节)
OGCMX:old代的最大容量(字节)
OGC:old代当前新生成的容量 (字节)
OC:Old代的容量 (字节)
MCMN:metaspace(元空间)中初始化(最小)的大小 (字节)
MCMX:metaspace(元空间)的最大容量 (字节)
MC:metaspace(元空间)当前新生成的容量 (字节)
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC:从应用程序启动到采样时年轻代中gc次数
FGC:从应用程序启动到采样时old代(全gc)gc次数

示例五:-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:最小元数据容量
MCMX:最大元数据容量
MC:当前元数据空间大小
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC:从应用程序启动到采样时年轻代中gc次数
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(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:年轻代中第一个survivor(幸存区)的容量 (字节)
S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
TT:持有次数限制
MTT:最大持有次数限制
DSS:期望的幸存区大小
EC:年轻代中Eden(伊甸园)的容量 (字节)
EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
YGC:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(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)中初始化(最小)的大小(字节)
NGCMX:年轻代(young)的最大容量 (字节)
NGC:年轻代(young)中当前的容量 (字节)
S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (字节)
S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
S1CMX:年轻代中第二个survivor(幸存区)的最大容量 (字节)
S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
ECMX:年轻代中Eden(伊甸园)的最大容量 (字节)
EC:年轻代中Eden(伊甸园)的容量 (字节)
YGC:从应用程序启动到采样时年轻代中gc次数
FGC:从应用程序启动到采样时old代(全gc)gc次数

示例八: -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(元空间)的容量 (字节)
MU:metaspace(元空间)目前已使用空间 (字节)
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
OC:Old代的容量 (字节)
OU:Old代目前已使用空间 (字节)
YGC:从应用程序启动到采样时年轻代中gc次数
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(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

统计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:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
O:old代已使用的占当前容量百分比
P:perm代已使用的占当前容量百分比
YGC:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)

示例十一:-gccause

显示垃圾回收的相关信息(通-gcutil),同时显示最后一次或当前正在发生的垃圾回收的诱因。

//语法: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:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
O:old代已使用的占当前容量百分比
P:perm代已使用的占当前容量百分比
YGC:从应用程序启动到采样时年轻代中gc次数

YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
LGCC:最后一次GC原因
GCC:当前GC原因(No GC 为当前没有执行GC)

示例十二: -printcompilation

当前VM执行的信息。

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

Compiled :编译任务的数目
Size :方法生成的字节码的大小
Type:编译类型
Method:类名和方法名用来标识编译的方法。类名使用/做为一个命名空间分隔符。方法名是给定类中的方法。上述格式是由-XX:+PrintComplation选项进行设置的

jmap + MAT实战内存溢出

一、构建程序溢出代码

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<?>>();

    /**
     * 堆内存溢出
     * VM参数:-Xms16m -Xmx16m
     * */
    @GetMapping("/heap")
    public void Test() {
        while (true) {
            int i = 0;
            userList.add(new User(++i, UUID.randomUUID().toString()));
        }
    }

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

2. 实体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是为了方便调用defineClass方法,因为该方法的定义为protected
 * */
public class Metaspace extends ClassLoader {
    public static List<Class<?>> CreateClasses() {
        // 类持有
        List<Class<?>> classes = new ArrayList<Class<?>>();
        // 循环1000w次生成1000w个不同的类。
        for (int i = 0; i < 10000000; ++i) {
            ClassWriter cw = new ClassWriter(0);
            // 定义一个类名称为Class{i},它的访问域为public,父类为java.lang.Object,不实现任何接口
            cw.visit(V1_1, ACC_PUBLIC, "Class" + i, null,
                    "java/lang/Object", null);
            // 定义构造函数<init>方法
            MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>",
                    "()V", null, null);
            // 第一个指令为加载this
            mw.visitVarInsn(ALOAD, 0);
            // 第二个指令为调用父类Object的构造函数
            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参数
heap:-Xms16m -Xmx16m
nonheap:-XX:MetaspaceSize=16M -XX:MaxMetaspaceSize=16M

二、导出内存映像文件

1. 内存溢出自动导出

-XX:+HeapDumpOnOutOfMemoryError  //当发生内存溢出的时候导出
-XX:HeapDumpPath=./             //导出目录

2. 使用jmap命令手动导出

[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分析内存溢出

1. 工具下载

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

//我使用的是MemoryAnalyzer-1.9.0版本。MAT不同版本按键位置或功能可能会有不同。

2. 将堆信息导入到mat中分析
File --> Open Heap Dump.. --> Leak Suspects Report --> Finish

3. 生成分析报告

具体使用参考:https://www.jianshu.com/p/54c8e11750e4

jstack实战死循环与死锁

打印Java进程,核心文件或远程调试服务器的Java线程堆栈跟踪。此命令是实验性的,不受支持。
官网地址: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已经被 Thread2占有了
     *    Thread2中想要获取的locak1已经被 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最大的进程号
top -p pid -H

//控制台输出线程的dump信息
jstack pid

printf "%s"  //转化成十进制
printf "%x" //转化成十六进制

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

//死锁结果如下 :
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.
死循环CPU飙高

1. DEMO


    /**
     * 死循环
     * */
    @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\"}]}
        //上面是正常的数据
        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. 问题排查

//启动项目
nohup java -jar xx.jar &

//找到占用CPU最大的进程号
top

//查看具体进程线程信息
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

//转化成十六进制
printf "%x" 47174
//printf "%s"  //转化成十进制
//printf "%x" //转化成十六进制

//控制台输出线程的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)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容