接下来根据详细的栗子,说明GC日志的查看,JVM参数的调整。

JVM参数配置

工作中常用的JVM参数配置,及如何调优。

JVM参数类型

  • 标准参数(-),JVM各个版本基本保持不变,相对稳定且向后兼容;
  • 非标准参数(-X),变化较小的参数,默认JVM实现参数,且不保证向后兼容;
  • 非Stable参数(-XX),各个JVM的实现不同,将来可能会取消。

标准参数

标准参数可以输入java查看:

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
48
49
50
用法: java [-options] class [args...]
(执行类)
或 java [-options] -jar jarfile [args...]
(执行 jar 文件)
其中选项包括:
-d32 使用 32 位数据模型 (如果可用)
-d64 使用 64 位数据模型 (如果可用)
-server 选择 "server" VM
默认 VM 是 server.

-cp <目录和 zip/jar 文件的类搜索路径>
-classpath <目录和 zip/jar 文件的类搜索路径>
用 ; 分隔的目录, JAR 档案
和 ZIP 档案列表, 用于搜索类文件。
-D<名称>=<值>
设置系统属性
-verbose:[class|gc|jni]
启用详细输出
-version 输出产品版本并退出
-version:<值>
警告: 此功能已过时, 将在
未来发行版中删除。
需要指定的版本才能运行
-showversion 输出产品版本并继续
-jre-restrict-search | -no-jre-restrict-search
警告: 此功能已过时, 将在
未来发行版中删除。
在版本搜索中包括/排除用户专用 JRE
-? -help 输出此帮助消息
-X 输出非标准选项的帮助
-ea[:<packagename>...|:<classname>]
-enableassertions[:<packagename>...|:<classname>]
按指定的粒度启用断言
-da[:<packagename>...|:<classname>]
-disableassertions[:<packagename>...|:<classname>]
禁用具有指定粒度的断言
-esa | -enablesystemassertions
启用系统断言
-dsa | -disablesystemassertions
禁用系统断言
-agentlib:<libname>[=<选项>]
加载本机代理库 <libname>, 例如 -agentlib:hprof
另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
-agentpath:<pathname>[=<选项>]
按完整路径名加载本机代理库
-javaagent:<jarpath>[=<选项>]
加载 Java 编程语言代理, 请参阅 java.lang.instrument
-splash:<imagepath>
使用指定的图像显示启动屏幕
有关详细信息, 请参阅 http://www.oracle.com/technetwork/java/javase/documentation/index.html。

非标准参数

非标准参数可以输入:java -X查看:

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
-Xmixed           混合模式执行(默认)
-Xint 仅解释模式执行
-Xbootclasspath:<用 ; 分隔的目录和 zip/jar 文件>设置引导类和资源的搜索路径
-Xbootclasspath/a:<用 ; 分隔的目录和 zip/jar 文件>附加在引导类路径末尾
-Xbootclasspath/p:<用 ; 分隔的目录和 zip/jar 文件>置于引导类路径之前
-Xdiag 显示附加诊断消息
-Xnoclassgc 禁用类垃圾收集
-Xincgc 启用增量垃圾收集
-Xloggc:<file> 将 GC 状态记录在文件中(带时间戳)
-Xbatch 禁用后台编译
-Xms<size> 设置初始 Java 堆大小
-Xmx<size> 设置最大 Java 堆大小
-Xss<size> 设置 Java 线程堆栈大小
-Xprof 输出 cpu 分析数据
-Xfuture 启用最严格的检查,预计会成为将来的默认值
-Xrs 减少 Java/VM 对操作系统信号的使用(请参阅文档)
-Xcheck:jni 对 JNI 函数执行其他检查
-Xshare:off 不尝试使用共享类数据
-Xshare:auto 在可能的情况下使用共享类数据(默认)
-Xshare:on 要求使用共享类数据,否则将失败。
-XshowSettings 显示所有设置并继续
-XshowSettings:system(仅限 Linux)显示系统或容器配置并继续
-XshowSettings:all显示所有设置并继续
-XshowSettings:vm 显示所有与 vm 相关的设置并继续
-XshowSettings:properties显示所有属性设置并继续
-XshowSettings:locale显示所有与区域设置相关的设置并继续

-X 选项是非标准选项。如有更改,恕不另行通知。

非stable参数

使用-XX:+PrintFlagsInitial查看初始属性。
主要分为键值对布尔型参数。
键值对
-XX:属性key=属性value,比如,-XX:MetaspaceSize=128m表示设置元空间的大小。
布尔型
-XX:+属性值(开启)/-属性值(关闭),比如,-XX:+PrintGCDetails打印GC的细节。

常用参数配置

参数名称 含义 默认值 说明
-Xms 初始堆大小 内存的1/64 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.
-Xmx 最大堆大小 内存的1/4 默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制.
-Xmn 年轻代的大小 整个堆的3/8
-Xss 每个线程堆栈的大小 一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k
-XX:NewSize 年轻代的大小
-XX:NewRatio 年轻代比例 配置年老代和年轻代的比例,如2,则年老与年轻比为:2:1
-XX:SurvivorRatio Eden区和Survivor区的大小比值 8 默认为8,则Eden和两个Survivor的比值为8:1:1
-XX:PretenureSizeThreshold 对象超过多大时直接再老年代分配 单位为字节
-XX:MaxTenuringThreshold 垃圾最大的年龄 15,Java8 如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概率 该参数只有在串行GC时才有效.
-XX:+HeapDumpOnOutOfMemoryError 堆栈溢出时导出dump文件 可以使用MAT分析

注:
SurvivorRatio的计算公式如下:
R为SurvivorRatio的值,Y为新生代的值,则:

SurvivorRatio是R,则比例就是R:1:1

并行收集器相关参数:

参数名称 含义 默认值 说明
-XX:+UseParNewGC 设置年轻代为并行收集 可与CMS收集同时使用 JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值
-XX:+UseParallelOldGC 设置老年代为并行收集器
-XX:ParallelGCThreads 并行收集器的线程数 此值最好配置与处理器数目相等 同样适用于CMS
-XX:MaxGCPauseMillis 每次年轻代垃圾回收的最长时间(最大暂停时间) 如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值.
-XX:+UseAdaptiveSizePolicy 自动选择年轻代区大小和相应的Survivor区比例 设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开.
-XX:GCTimeRatio 设置垃圾回收时间占程序运行时间的百分比

CMS相关参数

参数名称 含义 默认值 说明
-XX:+UseConcMarkSweepGC 使用CMS收集器
-XX:CMSFullGCsBeforeCompaction 多少次后压缩存储 运行多少次GC后,整理碎片。
-XX:+CMSParallelRemarkEnabled 降低标记停顿
-XX+UseCMSCompactAtFullCollection 在FULL GC的时候, 对年老代的压缩 CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。 可能会影响性能,但是可以消除碎片
-XX:CMSInitiatingOccupancyFraction 使用cms作为垃圾回收 使用百分之多少后开始CMS收集 92 因为CMS并发清除垃圾,会导致一边生成一边清理,因此不能占满后才开始清除,可以设置70,当出现promotion failed时,还要根据需要减小设置。

辅助信息

参数 含义 说明
-XX:+PrintGC 输出GC日志 回收前后内存及耗时
-XX:+PrintGCDetails 输出较详细的GC日志 包括GC的收集器名称
-XX:+PrintGCTimeStamps 输出耗时时间戳
-XX:+PrintGCApplicationStoppedTime 打印垃圾回收期间程序暂停的时间.可与上面混合使用
-XX:+PrintHeapAtGC 打印GC前后的详细堆栈信息
-Xloggc:filename 把相关日志信息记录到文件以便分析. 与上面几个配合使用
-XX:+PrintTLAB 查看TLAB空间的使用情况

工具的使用

MAT分析堆转储文件

线上程序运行的时候,可以加上-XX:+HeapDumpOnOutOfMemoryError参数来导出内存溢出时的堆信息,生成 hrof 文件, 添加-XX:HeapDumpPath可以指定 hprof 文件的生成路径,如果不指定则 hrof 文件生成在与字节码文件相同的目录下。
下载MemoryAnalyzer

将生成的hprof文件导入后,可以根据报告,找到内存溢出的错误发生的位置。

VisualVM

jdk自带的分析工具,可以连接到本地运行的java程序,通过丰富的插件来观察运行过程中的JVM使用情况。

jconsole

也是JDK自带的工具,可以远程连接java程序查看运行状况。

GC日志的分析

日志如下

1
2
10.703: [GC (Allocation Failure) 10.703: [DefNew: 8192K->1024K(9216K), 0.0105346 secs] 8192K->3547K(19456K), 0.0106322 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] 
40.239: [Full GC (Allocation Failure) 40.239: [Tenured: 10239K->10077K(10240K), 0.0177828 secs] 10277K->10077K(19456K), [Metaspace: 9308K->9308K(1058816K)], 0.0178940 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]

开头的时间表示自虚拟机启动后的时间。
GCFull GC表示垃圾收集的类型,Full GC会有STW,有一定的停顿时间;
Allocation Failure表示触发GC的原因;
DefNewTenuredMetaspace表示发生GC的区域,与用到的收集器有关,如Serial收集器就为DefNew,如果是ParNew收集器则名称为ParNew;
** 8192K->1024K(9216K)表示:GC 前该内存区域已使用容量 -> GC 后该内存区域已使用容量(该内存区域总容量);
**0.0105346 secs
表示整个GC所用的时间,如果多个区域GC则表示是每个区域的耗时;
Times: user=0.02 sys=0.00, real=0.02 secs代表用户态消耗的 CPU 时间,内核态消耗的 CPU 时间,和操作从开始到结束所经过的墙钟时间,墙钟时间包括各种非运算的等待耗时,例如等待磁盘 I/O,等待线程阻塞,而 CPU 时间不包括这些耗时,但当系统有多 CPU 或者多核的话,多线程操作会叠加这些 CPU 时间,所以 user 或 sys 时间是可能超过 real 时间的。