JDK 工具使用以及 CPU 100%排查过程、OOM排查

常用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 解决 docker 容器不能使用 jmap
docker run --name bff01 --cap-add=SYS_PTRACE ...

# 我的测试站 jvm 参数
" -Xms4g -Xmx4g -Xmn2g -Xss1m -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ "

# docker 直接打印 GC情况
docker exec -it bff01 jstat -gcutil $(docker exec -it bff01 jps | grep jar | awk '{print $1}') 1000

# docker 直接打印 jmap情况
docker exec -it bff01 jmap -heap $(docker exec -it bff01 jps | grep jar | awk '{print $1}')

# 显示所有 class的实例,数量,内存大小
jmap -histo 7 | head -n 15

# 查看有哪些线程在跑(线程名称自己定义)
jstack 7 | grep TaskThread- | awk '{print $1}' | sort -nt "-" -k 2 | cat -n

# 查看 java pid
jps

# 显示 jar
jps -l

# 显示参数
jps -v

# 输出配置信息
jinfo -flags 7

jps

虚拟机进程状况工具

1
2
3
4
5
6
7
8
9
10
jps # 查看 pid
7 jar
15580 Jps

jps -l # 显示 jar
7 /app.jar

jps -v # 显示参数
7 jar -Dserver.port=9080 -Dspring.profiles.active=production -Xms8g -Xmx8g -Xmn4g -Xss1m -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./
15613 Jps -Dapplication.home=/opt/java/openjdk -Xms8m

jinfo

Java配置信息工具

1
2
3
4
5
6
7
jinfo -flags 7 # 输出配置信息
Attaching to process ID 7, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.292-b10
Non-default VM flags: -XX:CICompilerCount=3 -XX:CompressedClassSpaceSize=528482304 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=null -XX:InitialHeapSize=8589934592 -XX:MaxHeapSize=8589934592 -XX:MaxMetaspaceSize=536870912 -XX:MaxNewSize=4294967296 -XX:MetaspaceSize=536870912 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=4294967296 -XX:OldSize=4294967296 -XX:ThreadStackSize=1024 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
Command line: -Dserver.port=9080 -Dspring.profiles.active=production -Xms8g -Xmx8g -Xmn4g -Xss1m -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./

JVM 参数

Java平台,标准版工具参考 - Java8官方文档

在这里插入图片描述

1
2
3
4
5
-Dxxx 标注参数

-XX 非标准参数
-XX:+PrintFlagsFinal 设置参数
-XX:-PrintFlagsFinal 取消参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
java -version # 查看java版本
openjdk version "1.8.0_292"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.292-b10, mixed mode)


java -XX:+PrintFlagsFinal -version # 打印参数信息
[Global flags]
intx ActiveProcessorCount = -1 {product}
...省略
bool AggressiveOpts = false {product}
intx AliasLevel = 3 {C2 product}
bool AlignVector = false {C2 product}
intx AllocateInstancePrefetchLines = 1 {product}
intx AllocatePrefetchDistance = 192 {product}
intx AllocatePrefetchInstr = 3 {product}
...省略
double CMSSmallCoalSurplusPercent = 1.050000 {product}
double CMSSmallSplitSurplusPercent = 1.100000 {product}
bool CMSSplitIndexedFreeListBlocks = true {product}
intx CMSTriggerInterval = -1 {manageable}
uintx CMSTriggerRatio = 80 {product}
intx CMSWaitDuration = 2000 {manageable}
uintx CMSWorkQueueDrainThreshold = 10 {product}
...省略
bool UseXmmLoadAndClearUpper = true {ARCH product}
bool UseXmmRegToRegMoveAll = true {ARCH product}
bool VMThreadHintNoPreempt = false {product}
intx VMThreadPriority = -1 {product}
intx VMThreadStackSize = 1024 {pd product}
intx ValueMapInitialSize = 11 {C1 product}
intx ValueMapMaxLoopSize = 8 {C1 product}
intx ValueSearchLimit = 1000 {C2 product}
bool VerifyMergedCPBytecodes = true {product}
bool VerifySharedSpaces = false {product}
intx WorkAroundNPTLTimedWaitHang = 1 {product}
uintx YoungGenerationSizeIncrement = 20 {product}
uintx YoungGenerationSizeSupplement = 80 {product}
uintx YoungGenerationSizeSupplementDecay = 8 {product}
uintx YoungPLABSize = 4096 {product}
bool ZeroTLAB = false {product}
intx hashCode = 5 {product}
openjdk version "1.8.0_292"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.292-b10, mixed mode)

jstat

虚拟机统计信息监视工具

  • jstat -class 7

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Loaded  Bytes  Unloaded  Bytes     Time   
    17778 33005.8 114 150.1 5503.66



    Loaded 加载多少类
    Bytes 占用字节数
    Unloaded 不加载的类
    Bytes 占用字节数
    Time 加载耗时

    在这里插入图片描述

  • jstat -gcutil 7 1000一秒打印1次 gc日志。也可以加上次数,例如打印3次jstat -gcutil 7 1000 3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
      S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
    21.80 0.00 33.85 37.65 95.24 92.86 3325 949.517 4 5.613 955.130
    21.80 0.00 34.03 37.65 95.24 92.86 3325 949.517 4 5.613 955.130
    21.80 0.00 34.23 37.65 95.24 92.86 3325 949.517 4 5.613 955.130
    21.80 0.00 34.25 37.65 95.24 92.86 3325 949.517 4 5.613 955.130

    S0:幸存1区当前使用比例
    S1:幸存2区当前使用比例
    E:伊甸园区使用比例
    O:老年代使用比例
    M:元数据区使用比例
    CCS:压缩使用比例
    YGC:年轻代垃圾回收次数
    YGCT:年轻代垃圾回收消耗时间
    FGC:老年代垃圾回收次数
    FGCT:老年代垃圾回收消耗时间
    GCT:垃圾回收消耗总时间

jmap

Java内存映射工具

生成堆储存快照,dump文件

  • jmap -heap 7显示堆,及使用情况(具体含义,参考下面案例)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    Attaching to process ID 7, please wait...
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.292-b10

    using thread-local object allocation.
    Parallel GC with 4 thread(s)

    Heap Configuration:
    MinHeapFreeRatio = 0
    MaxHeapFreeRatio = 100
    MaxHeapSize = 8589934592 (8192.0MB)
    NewSize = 4294967296 (4096.0MB)
    MaxNewSize = 4294967296 (4096.0MB)
    OldSize = 4294967296 (4096.0MB)
    NewRatio = 2
    SurvivorRatio = 8
    MetaspaceSize = 536870912 (512.0MB)
    CompressedClassSpaceSize = 528482304 (504.0MB)
    MaxMetaspaceSize = 536870912 (512.0MB)
    G1HeapRegionSize = 0 (0.0MB)

    Heap Usage:
    PS Young Generation
    Eden Space:
    capacity = 3699376128 (3528.0MB)
    used = 162589232 (155.0571746826172MB)
    free = 3536786896 (3372.942825317383MB)
    4.395044633861032% used
    From Space:
    capacity = 304611328 (290.5MB)
    used = 57984432 (55.29826354980469MB)
    free = 246626896 (235.2017364501953MB)
    19.03554683297924% used
    To Space:
    capacity = 290979840 (277.5MB)
    used = 0 (0.0MB)
    free = 290979840 (277.5MB)
    0.0% used
    PS Old Generation
    capacity = 4294967296 (4096.0MB)
    used = 1970283200 (1879.0084838867188MB)
    free = 2324684096 (2216.9915161132812MB)
    45.874230563640594% used

    41044 interned Strings occupying 4547200 bytes.

含义解释:
NewRatio SurvivorRatio

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# docker exec -it bff01 jmap -heap $(docker exec -it bff01 jps | grep jar | awk '{print $1}')
Attaching to process ID 6, please wait... # 附上进程ID 6,请稍候…
Debugger attached successfully. # 调试器连接成功。
Server compiler detected. # 服务器编译器检测到。
JVM version is 25.292-b10 # JVM版本是25.292-b10

using thread-local object allocation. # 使用线程本地对象分配。
Parallel GC with 2 thread(s) # 使用2个线程的并行GC

Heap Configuration: # 堆配置:
MinHeapFreeRatio = 0 # 最小空闲堆占比
MaxHeapFreeRatio = 100 # 最大空闲堆占比
MaxHeapSize = 2051014656 (1956.0MB) # 最大堆大小
NewSize = 42991616 (41.0MB) # 新生代大小(解释见上图)
MaxNewSize = 683671552 (652.0MB) # 最大新生代大小
OldSize = 87031808 (83.0MB) # 老年代大小
NewRatio = 2 # 新生代比例(解释见上图)
SurvivorRatio = 8 # 幸存者比例(解释见上图)
MetaspaceSize = 21807104 (20.796875MB) # 元空间大小
CompressedClassSpaceSize = 1073741824 (1024.0MB) # 压缩类空间大小
MaxMetaspaceSize = 17592186044415 MB # 最大元空间大小
G1HeapRegionSize = 0 (0.0MB) # G1堆 Region 大小

Heap Usage: # 堆使用情况:
PS Young Generation # 年轻代
Eden Space: # eden 区
capacity = 426770432 (407.0MB) # 容量
used = 135677944 (129.39257049560547MB) # 已使用量
free = 291092488 (277.60742950439453MB) # 剩余量
31.791786362556625% used # 使用率
From Space: # from 区
capacity = 12058624 (11.5MB) # 容量
used = 0 (0.0MB) # 已使用量
free = 12058624 (11.5MB) # 剩余量
0.0% used # 使用率
To Space: # to 区
capacity = 13631488 (13.0MB) # 容量
used = 0 (0.0MB) # 已使用量
free = 13631488 (13.0MB) # 剩余量
0.0% used # 使用率
PS Old Generation # 老年代
capacity = 94896128 (90.5MB) # 容量
used = 19645160 (18.735084533691406MB) # 已使用量
free = 75250968 (71.7649154663086MB) # 剩余量
20.701750865957354% used # 使用率

13681 interned Strings occupying 1252832 bytes. # 字符串常量池 一共有 13681 个,占用 1252832 字节。
  • jmap -histo 7 | head -n 15显示所有 class的实例,数量,内存大小

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     num     #instances         #bytes  class name
    ----------------------------------------------
    1: 693235 535837592 [B
    2: 4836578 487571688 [C
    3: 4808399 115401576 java.lang.String
    4: 1338286 106654600 [Ljava.lang.Object;
    5: 2554225 102169000 java.util.LinkedHashMap$Entry
    6: 1109240 88777440 [Ljava.util.WeakHashMap$Entry;
    7: 131390 87379360 [I
    8: 79970 74820496 [J
    9: 1109233 53243184 java.util.WeakHashMap
    10: 410747 46003664 org.springframework.boot.loader.jar.JarFile
    11: 450870 38262672 [Ljava.util.HashMap$Node;
    12: 1154904 36956928 java.lang.ref.ReferenceQueue
  • jmap -dump:live,format=b,file=heap.bin 7手动导出dump日志,不加路径默认导入到当前文件夹

jstack

Java堆栈跟踪工具

可以排查死锁

  • jstack 7 | grep deadlock
    在这里插入图片描述

  • jstack 7 | grep Thread.State | sort | uniq线程的状态有哪些

    1
    2
    3
    4
    5
    6
    java.lang.Thread.State: RUNNABLE
    java.lang.Thread.State: TIMED_WAITING (on object monitor)
    java.lang.Thread.State: TIMED_WAITING (parking)
    java.lang.Thread.State: TIMED_WAITING (sleeping)
    java.lang.Thread.State: WAITING (on object monitor)
    java.lang.Thread.State: WAITING (parking)
  • jstack 7 | grep TaskThread- | awk '{print $1}' | sort -nt "-" -k 2 | cat -n查看有哪些线程在跑(线程名称自己定义)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     1  "JdRdsFetchTaskThread-30"
    2 "KafkaTaskThread-31"
    3 "ApiFetchTaskThread-35"
    4 "KafkaTaskThread-36"
    5 "ApiFetchTaskThread-37"
    6 "KafkaTaskThread-38"
    7 "KafkaTaskThread-39"
    8 "ApiFetchTaskThread-40"
    9 "KafkaTaskThread-41"
    10 "KafkaTaskThread-42"
    11 "KafkaTaskThread-44"
    12 "KafkaTaskThread-45"
    13 "ApiFetchTaskThread-47"
    14 "KafkaTaskThread-48"
    15 "KafkaTaskThread-62"
    16 "ApiFetchTaskThread-64"
    17 "KafkaTaskThread-65"
    18 "ApiFetchTaskThread-66"
    19 "KafkaTaskThread-67"

CPU 100% 排查

1、执行java -cp app.jar -XX:+PrintGC -Xmx200M -Xmx200M com.taopanfeng.FullGCProblem
解释:最小堆200M,最大堆200M,并打印GC信息。使用 -cp app.jar 需要指定main方法的类 也就是 com.taopanfeng.FullGCProblem。

这个程序会一直往线程池队列中扔数据。每扔一条数据就要创建100个UserInfo对象。因为存在队列中,所以这100个对象不能被垃圾回收,所以内存会越来越占用过大。而我们启动时,设置堆内存200M又很小,所以会频繁GC。
在这里插入图片描述

2、top命令,上面显示整理情况,下面显示进程。
为什么有些进程可以超过 100%,是因为下面是按照核心来算的。例如:两个核心,最大是200%。
上面显示的才是总的 cpu 使用率。

记住 pid 后面要用到。
在这里插入图片描述

3、top -p 5943监控单个进程,进入监控界面,此时输入 H 显示进程下的所有线程。
在这里插入图片描述
在这里插入图片描述

占用过高的有两个线程 5945,5946。

4、使用工具 在线进制转换 ,把这两个线程换算成 16进制。
在这里插入图片描述

5、使用命令 jstack 5943 查看 java 进程的所有线程信息。搜索5945,5946的十六进制 1739,173a。

发现,两个线程都是 GC线程。CPU 都被 GC 给吃掉了。
在这里插入图片描述

6、查看 GC 信息。jstat -gcutil 5943 1000一秒刷新一次,发现频繁的进行 full gc

7、jmap -heap 5943查看堆的使用情况。eden from to都满了,old也 99%。所以,会频繁 full gc。

1
2
3
4
# 内存过高还可能存在其他问题
+ 超出预期访问量
+ 内存泄漏
+ 代码问题

在这里插入图片描述

8、查看到哪些对象占用过高

1
2
3
4
5
6
7
8
9
10
11
12
class name对应的就是Class文件里的class的标识
B代表byte
C代表char
D代表double
F代表float
I代表int
J代表long
Z代表boolean

前边有[代表数组,[I 就相当于int[]

对象用[L+类名表示

在这里插入图片描述

OOM排查

方式1、启动前加入参数:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ ,即使发生 OOM 也会有日志可以分析
详情参考:Java平台,标准版工具参考 - Java8官方文档
在这里插入图片描述

方式2、未发生 OOM,可以进行日志 dump 下面,使用工具进行分析。
未 OOM jmap -dump:live,format=b,file=heap.bin 7导出dump日志,不加路径默认导入到当前文件夹
在这里插入图片描述