JVM参数类型

标准参数

在各个JVM版本中基本不变,相对稳定

1
2
# 查看jdk版本
java -version

X参数:非标准化参数

在各个版本中有可能会发生变化,相对稳定

1
2
3
4
5
6
# -Xint:解释执行
java -Xint -version
# -Xcomp:第一次使用就编译成本地代码
java -Xcomp -version
# -Xmixed:混合模式,JVM自己决定是否编译成本地代码
java -Xmixed -version

XX参数:非标准化参数,主要用于 JVM 调优和 Debug

  • Boolean类型
    1
    2
    3
    # -XX:[+/-]<name> 表示启用或者禁用name属性,+表示启用,-表示禁用
    -XX:+UseConcMarkSweepGC
    -XX:-UseG1GC
  • 非Boolean类型
    1
    2
    3
    4
    5
    6
    # -XX:<name>=<value> 表示设置name属性的值
    -XX:MaxGCPauseMillis=500
    -XX:GCTimeRatio=19
    # 也存在缩写版本,看上去是X参数,其实是XX参数
    # -Xmx:最大堆内存 对应 -XX:MaxHeapSize
    # -Xms:初始堆内存 对应 -XX:InitialHeapSize

查看运行时JVM参数

1
2
3
4
5
6
7
8
9
10
# 查看初始值
-XX:+PrintFlagsInitial
# 查看最终的值
-XX:+PrintFlagsFinal
# 解锁实验参数
-XX:+UnlockExperimentalVMOptions
# 解锁诊断参数
-XX:+UnlockDiagnosticVMOptions
# 打印命令行参数
-XX:+PrintCommandLineFlags

PrintFlagsFinal

1
2
3
4
5
6
7
8
9
java -XX:+PrintFlagsInitial -version
[Global flags]
intx ActiveProcessorCount = -1 uintx
MaxHeapSize := 4294967296 {product}
bool UseThreadPriorities = true {pd product}
bool UseTypeProfile = true {product}
bool UseTypeSpeculation = true {C2 product}
# = 表示默认值,:= 表示被用户或则 JVM 修改后的值
# 这个命令查看的是当前运行这个命令的进程 java -XX:+PrintFlagsInitial -version 的值,运行这一条,也会去启动一个 java 进程,那么打印的参数则是这个进程的参数。

jps

jps是专门用来查看Java进程的工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(base)  fms231@qishichengdeMac-mini  ~  jps -help
usage: jps [--help]
jps [-q] [-mlvV] [<hostid>]

Definitions:
<hostid>: <hostname>[:<port>]
-? -h --help -help: Print this help message and exit.

# 查看当前的 java 进程,左侧是进程 ID,右侧是名称
(base) fms231@qishichengdeMac-mini  ~  jps
56945 Main
58280 Jps
57130 Launcher

# -l:显示完整的名称,显示应用程序main类的完整程序包名称或应用程序JAR文件的完整路径名
(base) fms231@qishichengdeMac-mini  ~  jps -l
56945 com.intellij.idea.Main
57130 org.jetbrains.jps.cmdline.Launcher
58238 jdk.jcmd/sun.tools.jps.Jps

jinfo

查看正在运行的 JVM 进程信息

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
(base)  fms231@qishichengdeMac-mini  ~  jinfo -help
Usage:
jinfo <option> <pid>
(to connect to a running process)

where <option> is one of:
-flag <name> to print the value of the named VM flag
-flag [+|-]<name> to enable or disable the named VM flag
-flag <name>=<value> to set the named VM flag to the given value
-flags to print VM flags
-sysprops to print Java system properties
<no option> to print both VM flags and system properties
-? | -h | --help | -help to print this help message

# 查看某一JVM进程的最大堆内存
# 比如idea上的最大堆内存
(base) fms231@qishichengdeMac-mini  ~  jinfo -flag MaxHeapSize 57130
-XX:MaxHeapSize=738197504
# 单位为byte,也就是说这个进程的最大堆内存是738197504byte,也就是704MB

# -flags 查看非 JVM 默认参数信息
(base) fms231@qishichengdeMac-mini  ~  jinfo -flags 57130
VM Flags:
-XX:CICompilerCount=4 -XX:ConcGCThreads=2 -XX:G1ConcRefinementThreads=9 -XX:G1EagerReclaimRemSetThreshold=8 -XX:G1HeapRegionSize=1048576 -XX:GCDrainStackTargetSize=64 -XX:InitialHeapSize=536870912 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=738197504 -XX:MaxNewSize=442499072 -XX:MinHeapDeltaBytes=1048576 -XX:MinHeapSize=8388608 -XX:NonNMethodCodeHeapSize=5839564 -XX:NonProfiledCodeHeapSize=122909338 -XX:ProfiledCodeHeapSize=122909338 -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:SoftMaxHeapSize=738197504 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC -XX:-UseNUMA -XX:-UseNUMAInterleaving

# 查看垃圾回收器
(base) fms231@qishichengdeMac-mini  ~  jinfo -flag UseConcMarkSwee
pGC 57130
no such flag 'UseConcMarkSweepGC'
(base) fms231@qishichengdeMac-mini  ~  jinfo -flag UseG1GC 57130
-XX:+UseG1GC
(base) fms231@qishichengdeMac-mini  ~  jinfo -flag UseParallelGC 57130
-XX:-UseParallelGC
# 在jdk17中,CMS已经被移除

查看JVM统计信息

jstat可以查询以下

  • 类加载
  • 垃圾回收
  • JIT编译

语法

1
jstat [ generalOption | outputOptions vmid [ interval[s|ms] [ count ] ]

generalOption:单个常规命令行选项
可以通过 jstat -options 输出支持的命令,比如常见的有
- class:类加载
- compiler:JIT 编译信息
- gc:垃圾回收信息
- printcompilation:显示Java HotSpot VM编译方法统计信息
outputOptions:一个或由单个的多输出选项
vmid:虚拟机标识符,一般用进程 id,还可以写完整的远程服务器上的进程 id
interval:采样间隔,默认单位是毫秒(可以为秒),制定后,则间隔多长时间输出一次
count:要显示的样本数量,也就是输出几次

类装载信息

1
2
3
mrcode:~ mrcode$ jstat -class 46129
Loaded Bytes Unloaded Bytes Time
3315 6334.5 0 0.0 1.36

类加载器统计信息:
- Loaded:已加载的类数。
- Bytes:加载的 kB 数。
- Unloaded:卸载的类数。
- Bytes:卸载的KB数。
- Time:执行类加载和卸载操作所花费的时间。

垃圾收集信息

  • gc
  • gcutil
  • gccause
  • gcnew
  • gcold
    1
    2
    3
    4
    5
    mrcode:~ mrcode$ jstat -gc 46129

    S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT

    10752.0 10752.0 0.0 4479.4 65536.0 15266.7 175104.0 144.0 18048.0 17391.3 2176.0 2004.6 1 0.004 0 0.000 0.004
  • S0C、S1C、S0U、S1US0S1的总量与使用量
  • EC、EUEden区总量与使用量
  • OC、OUOld区总量与使用量
  • MC、MUMetaspace区总量与使用量
  • CCSC、CCSU:压缩类空间总量与使用量
  • YGC、YGCTYoungGC的次数与时间
  • FGC、FGCTFullGC的次数与时间
  • GCT:总的GC时间

JIT编译信息

  • compiler:显示有关 Java HotSpot VM 即时编译器行为的统计信息。
  • printcompilation:显示 Java HotSpot VM 编译方法统计信息。
    1
    2
    3
    mrcode:~ mrcode$ jstat -compiler 47503
    Compiled Failed Invalid Time FailedType FailedMethod
    24 0 0 0.02 0
  • Compiled:执行的编译任务数。
  • Failed:编译任务数失败。
  • Invalid:无效的编译任务数。
  • Time:执行编译任务所花费的时间。
  • FailedType:上次失败的编译的编译类型。
  • FailedMethod:上次失败的编译的类名和方法。
1
2
3
mrcode:~ mrcode$ jstat -printcompilation 47503
Compiled Size Type Method
24 5 1 java/net/URL getAuthority
  • Compiled:由最近编译的方法执行的编译任务数。
  • Size:最近编译的方法的字节码的字节数
  • Type:最近编译的方法的编译类型
  • Method:最近编译的方法的类名和方法名

jmap + MAR 内存溢出

制造堆内存溢出

1
2
Exception in thread "http-nio-8080-exec-1" java.lang.OutOfMemoryError: GC overhead limit exceeded
Exception in thread "ContainerBackgroundProcessor[StandardEngine[Tomcat]]" java.lang.OutOfMemoryError: GC overhead limit exceeded

参考https://zq99299.github.io/note-book2/monitor-tuning/01/04.html#%E5%88%B6%E9%80%A0%E9%9D%9E%E5%A0%86%E5%86%85%E5%AD%98%E6%BA%A2%E5%87%BA

制造非堆内存溢出

1
2
Exception in thread "http-nio-8080-exec-1" java.lang.OutOfMemoryError: Metaspace
Exception in thread "ContainerBackgroundProcessor[StandardEngine[Tomcat]]" java.lang.OutOfMemoryError: Metaspace

参考https://zq99299.github.io/note-book2/monitor-tuning/01/04.html#%E5%88%B6%E9%80%A0%E9%9D%9E%E5%A0%86%E5%86%85%E5%AD%98%E6%BA%A2%E5%87%BA

导出内存映像文件

上面两种内存溢出,如何解决?
一般通过分析内存映像文件来找出到底是哪些类一直占用没有被释放,内存溢出有可能是内存泄露,也有可能是内存CPU不足.

  • C语言中的内存泄露指的是:new了一个对象,你把这个对象指针丢了,这块内存就永远得不到释放了
  • Java中的内存泄露指的是:new了一个对象,被一直持有,得不到释放。

内存溢出自动

当发生内存溢出的时候,自动导出 这些信息以供我们查询,可以通过如下参数达到

  • -XX:+HeapDumpOnOutOfMemoryError:启用内存溢出自动导出功能
  • -XX:HeapDumpPath=./:配置导出的文件存放在哪里
    导出文件为 .hprof 文件,可以通过jvisualvm工具打开查看

使用jmap手动导出

1
2
3
jmap [options] pid
jmap [options] executable core
jmap [options] [pid] server-id@ ] remote-hostname-or-ip

MAT 分析内存溢出

MAT 内存分析器是内存分析工具

jstack

jstack是一个Java堆栈跟踪工具,用于生成Java线程转储,可以用来诊断线程死锁、死循环、请求处理时间过长等问题。

1
2
3
4
5
jstack [ options ] pid

jstack [ options ] executable core

jstack [ options ] [ server-id@ ] remote-hostname-or-IP

Java线程状态

  • NEW:新建,该线程尚未启动。
  • RUNNABLE:运行,线程正在 JVM 中执行。
  • BLOCKED:阻塞,线程被阻塞,等待监视器锁定。
  • WAITING:等待,线程无限期地等待另一个线程执行特定操作。
  • TIMED_WAITING:限时等待,线程正在等待另一个线程执行操作,直到指定的等待时间。
  • TERMINATED:终止,线程已退出。

RoaringBitmap

内存占用相比List少了50倍

JVM调优

  1. 首先表态如果使用合理的JVM参数配置,在大多数情况应该是不需要调优的
  2. 其次说明可能还是存在少量场景需要调优,我们可以对一些JVM核心指标配置监控告警,当出现波动时认为介入分析评估
  3. 最后举一个实际的调优例子来加以说明