Java 虚拟机技术是每个 Java 开发工程师都应该深入掌握的。本系列文章将深入介绍 JVM 相关技术,主要包括内存划分、对象创建回收与分配以及垃圾收集三大部分。本系列文章将力求全面概要地汇总核心知识点,并使知识点串联成面,以方便学习、工作以及备忘复习。本文将介绍第三部分——垃圾收集。
垃圾收集算法
- 标记清除算法
- 需要标记的对象非常多,效率一般不高
- 内存容易导致空间碎片化问题
- 标记整理算法
- 在标记清除算法基础上,增加内存整理功能,避免碎片化的问题
- 同样存在标记量大而效率不高的问题
- 标记复制算法
- 一般需要预留 Survivor 区域,导致空间利用率不高
- 回收效率非常高
- 分代收集算法
- 常见的垃圾收集器都采用此法
常见垃圾收集器
经典垃圾收集器
新生代收集器
- Serial New 收集器(-XX:+UseSerialGC)
新生代单线程垃圾收集器。
- Parallel 收集器(-XX:+UseParallelGC):
也称为 Parallel Scavenge收集器,可以理解为 Serial New 收集器的多线程版本。该垃圾收集器可与 Serial Old 以及 Parallel Old 两款收集器搭配使用。
- ParNew 收集器(-XX:+UseParNewGC)
该垃圾收集器专门开发来与 CMS 收集器搭配使用,当然也可以与 Serial Old 垃圾收集器使用。
- Serial New 收集器(-XX:+UseSerialGC)
老年代收集器
- Serial Old 收集器(-XX:+UseSerialOldGC)
- Parallel Old 收集器(-XX:+UseParallelOldGC)
老年代并行垃圾收集器,仅与 Parallel 收集器搭配使用。
- CMS 收集器(-XX:+UseConcMarkSweepGC)
跨代收集器
- G1 收集器(-XX:+UseG1GC)
注意,在 jdk1.8.0_161 中测试发现 -XX:+UseSerialOldGC 参数已经不可用。目前各个垃圾收集器之间的关系图如下:
其中标红线表示 jdk1.8.0_161 之后推荐使用的搭配关系,此外 CMS 在并发失败的时候还会退化为 Serial Old。 从 JDK 源码也可以看出端倪:
CMS 垃圾收集器
简介
CMS (Concurrent Mark Sweep)是老年代垃圾收集器,内部使用标记清除算法。其一般与 ParNew 搭配使用。CMS 的回收模式一般分为两种background 和 foreground 两种模式。background模式下,一般划分为以下几个阶段:
- 初始标记:快速标记 GC Roots 直接引用的对象,该阶段为 Stop The World 过程;
- 并发标记:从 GC Roots 直接引用对象出发遍历其他存活对象,该过程与用户线程并发运行,因此可能会有已被标记的对象状态发生变化。该过程持续时间会比较长,但不会 STW;
- 重新标记:修正并发标记阶段状态发生变动的对象,该阶段停顿时间会比初始标记稍长,但远比并发标记要短暂。另外,CMS 主要采用了三色标记的增量更新算法实现重新标记;
- 并发清理:清理未标记的对象,该阶段与用户线程并发运行。同时根据三色标记原理,该阶段新增对象都会被标记为黑色而不必清理。
另外一种模式是 foreground ,该模式下 CMS 将会退化为与 Serial Old 相同的收集算法,也就是采用单线程串行 GC 模式,STW 时间超长,有时会长达十几秒。这种模式下才能准确称为 Full GC。
CMS 存在几个缺点:
- 对 CPU 资源敏感,会与应用程序争抢 CPU 资源;
- 并发标记和并发清理阶段会产生浮动垃圾,需要等待下一次 GC 过程才能回收;
- 标记清除算法会产生大量空间碎片(但可通过 -XX:+UseCMSCompactAtFullCollection 参数让 JVM 清理后进行内存整理);
- 在并发标记和并发清理阶段,GC 线程与用户线程并发执行,此时如果再次触发 Major GC,会引起 “concurrent mode failure”,此时会进入 STW 状态,并退化为使用 Serial Old 垃圾收集器来回收。
常用调优参数:
参数 | 参数含义 | 默认值 |
---|---|---|
-XX:+UseConcMarkSweepGC | 启用 CMS 收集器 | 默认搭配 ParNew 新生代收集器 |
-XX:ConcGCThreads | 并发的 GC 线程数量 | 默认值(CPU核心数+3)/ 4 |
-XX:+UseCMSCompactAtFullCollection | Full GC 后做压缩整理以减少内存碎片 | |
-XX:CMSFullGCsBeforeCompaction | 指定多少次 Full GC 后压缩整理一次 | 默认值是0,表示每次 Full GC 都会压缩一次 |
-XX:CMSInitiatingOccupancyFraction | 当老年代使用达到该比例会触发 Full GC | 默认值92(百分比) |
-XX:+UseCMSInitiatingOccupancyOnly | 表示仅使用设定的回收阈值(这里指CMSInitiatingOccupancyFraction),如果不指定,JVM仅在第一次使用设定阈值,后续则自动调整,所以一般设置了回收阈值都会同时设置该值。 | |
-XX:+CMSScavengeBeforeRemark | 在 Full GC 前执行一次 Minor GC,目的是减少老年代对年轻代的引用,从而降低标记阶段的开销 | |
-XX:+CMSParallelInitialMarkEnabled | 表示在初始标记的时候多线程执行从而缩短 STW | |
-XX:+CMSParallelRemarkEnabled | 表示在重新标记的时候多线程执行从而缩短 STW | 默认开启 |
GC 日志案例:
运行参数: -Xms50m -Xmx50m -XX:+UseConcMarkSweepGC -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128M -XX:+PrintGCDetails -XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSInitiatingOccupancyOnly
## 初始标记[GC (CMS Initial Mark) [1 CMS-initial-mark: 30614K(34176K)] 34916K(49536K), 0.0015545 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] ## 并发标记[CMS-concurrent-mark-start][CMS-concurrent-mark: 0.014/0.014 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] [CMS-concurrent-preclean-start][CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [CMS-concurrent-abortable-preclean-start][CMS-concurrent-abortable-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] ## 重新标记(最终标记)[GC (CMS Final Remark) [YG occupancy: 4302 K (15360 K)][Rescan (parallel) , 0.0008078 secs][weak refs processing, 0.0004334 secs][class unloading, 0.0038316 secs][scrub symbol table, 0.0038272 secs][scrub string table, 0.0003411 secs][1 CMS-remark: 30614K(34176K)] 34916K(49536K), 0.0093542 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] ## 并发清理[CMS-concurrent-sweep-start][CMS-concurrent-sweep: 0.003/0.003 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] ## 并发重置[CMS-concurrent-reset-start][CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
主要看点:
- 初始标记耗时非常短(0.0015545 secs),触发阈值约是90%(30614/34176≈90%),这值比参数指定值92%略小,但在预期之内;
- 并发标记阶段不会 STW,用时相对较长(0.014 secs);
- 重新标记阶段默认就是多线程(Rescan (parallel)),也就是说 CMSParallelRemarkEnabled 默认开启;
常见调优思路
Java中9种常见的CMS GC问题分析与解决
G1 垃圾收集器
简介
G1 垃圾收集器与 CMS 收集器非常相似,但存在本质的区别。读者可以先看下一篇《Java 虚拟机原理 (四) G1垃圾收集器入门》进行了解,此处不再重复。
下边直接来看 G1 的垃圾回收阶段图:
具体各个阶段总结如下:
回收阶段 | 是否 STW | 过程 |
---|---|---|
年轻代收集 (young gc) | 是(收集过程中复制移动动作是一个 STW 过程) | 1.使用复制算法,从 eden 区将存活对象转移到 survivor区;2.如果对象超过了老化阈值,则会被晋升到老年代区块中。 |
初始标记(initial-mark) | 是 | 1.当老年代占堆比重达到 IHOP 阈值(缺省45%),则会触发并发标记周期,并进入初始标记阶段;2.初始标记过程是伴随着一次年轻代收集同时完成的;3.该过程主要是标记那些引用了老年代对象的 Survivor 区块(也就是根区块) |
并发根区块扫描 (concurrent-root-scan) | 否 | 1.扫描那些引用了老年代的 Suvivor 区块(根区块)并标记他们所引用的对象。2.这个阶段是和应用线程并行执行。这个阶段必须在下一次 young gc 发生之前完成。 |
并发标记 (concurrent-mark) | 否 | 1.在全堆范围内寻找存活对象;2.该过程与应用线程并行执行;3.这个阶段可以被年轻代垃圾收集过程所打断(也就是中间可以穿插多个 young gc) |
重新标记 (remark) | 是 | 1.最终完成堆中所有存活对象的标记;2.这个阶段使用了一个叫SATB(snapshot-at-the-beginning)的算法,该算法比CMS收集器所用算法快非常多。 |
并发清理 (cleanup) | 是(重置空区块阶段(3)为并发操作) | 1.清算存活对象以及空区块 (STW);2.擦除 RSets (STW);3.重置空区块,并添加进空闲区块列表;4.该阶段还会决定是否进入空间回收周期。 |
空间回收周期(space reclamation | 是 | 1.该过程会疏散或者复制存活对象那到新的未使用区块上;2.这过程可以包含多次 young gc,可以发生在年轻代区块中,GC日志中显示为[GC pause (young)],或者同时发生在年轻代和老年代区块中,而GC日志中显示为[GC Pause (mixed)];3.当G1判断不再值得回收老年代区块以获取更多空间的时候,便会结束该阶段,并进入下一个年轻代收集循环。 |
注意!当 G1 在回收存活对象或者是晋升对象到老年代的时候发生堆空间不足,将会触发晋升失败。此时,G1将进入 STW,并使用单线程来进行 Full GC。如果调优到位的话,你的应用应该避免Full GC发生。
综上,G1 垃圾收集模式分为三种:
- Young GC:当 G1 评估当前年轻代的回收时间接近 -XX:MaxGCPauseMillis 指定值的时候,会触发 Young GC;
- Mixed GC:当 老年代占有率达到 -XX:InitiatingHeapOccupancyPercent 指定值的时候,会触发并发周期。而并发清理阶段阶段会判断是否需要进入空间回收周期。在空间回收周期内,会根据期望的GC停顿时间以及区块的回收价值等来决定是否进行以及进行多少次 Mixed GC;
- Full GC:STW,单线程收集过程。
常用调优参数:
参数 | 参数含义 | 默认值 |
---|---|---|
-XX:+UseG1GC | 指定使用 G1 垃圾收集器 | |
-XX:MaxGCPauseMillis=200 | 设定一个最大的GC停顿时间目标。这是一个软目标,JVM会尽最大努力满足这个目标。但不宜设置过小,以免因为每次回收垃圾过少而导致频繁 GC。 | 200 (ms) |
-XX:GCPauseTimeInterval= | GC 停顿间隔时间 | G1 在默认情况下不设置该值,而允许G1在一些极端的情况下连续执行垃圾回收 |
-XX:ParallelGCThreads= | 并行阶段最大的线程数 | 根据CPU核心数N进行计算,如果N=8,那么ParallelGCThreads=N*5/8 |
-XX:ConcGCThreads= | 并发阶段最大的线程数 | 默认值是-XX:ParallelGCThreads的值除以4 |
-XX:+G1UseAdaptiveIHOP-XX:InitiatingHeapOccupancyPercent=45 | 配置启用IHOP,以及配置触发比例 | 默认启用,触发比例为45%。注意,-XX:+G1UseAdaptiveIHOP这个选项会在JDK9里默认启用,即-XX:InitiatingHeapOccupancyPercent和XX:+GIUseAdaptivelHOP在JDK9之后只需要启用一个就可以了。JDK8环境下运行该选项会输出:“Unrecognized VM option ‘G1UseAdaptivelHOP’” |
-XX:G1HeapRegionSize= | 设置区块大小 | 整个堆最多划分为2048个Region,Region的大小一定是在1~32M之间,并且是2的N次方。 所以,如果堆的尺寸小于2G,那么Region数量就会少于2048。如果设置的堆大于64G,JVM会适当增加region的数量,但是region大小一定不会超过32M。 |
-XX:G1NewSizePercent=5-XX:G1MaxNewSizePercent=60 | 配置年轻代占比的最小值和最大值 | 最小值默认为5%,最大值默认为60% |
-XX:G1HeapWastePercent=5 | 允许浪费的堆内存比例。如果可回收百分比低于这个百分比,那么G1就不会触发Mixed GC。 | 默认值5% |
-XX:G1MixedGCCountTarget=8 | 设置空间清理阶段的回收次数 | 默认不超过8次 |
-XX:G1MixedGCLiveThresholdPercent=85 | 如果老年代区块内部存活对象超过该比例,那么在空间清理阶段不会将该区块加入 CSet,也就是不会对其进行回收 | 默认值85% |
-XX:G1ReservePercent=10 | 设置堆的保留空间阈值以降低发生晋升失败的可能。 | 默认值是10 |
-XX:G1OldCSetRegionThresholdPercent=10 | 设置Mixed GC期间要回收的老年代Region数量上限,即一次Mixed GC中最多可以被选入CSet中的老年代Region数量。 | 默认值10% |
GC 日志案例:
案例一
CommandLine flags: -XX:G1NewSizePercent=20 -XX:+HeapDumpOnOutOfMemoryError -XX:InitialHeapSize=3221225472 -XX:MaxGCPauseMillis=500 -XX:MaxHeapSize=5872025600 -XX:-OmitStackTraceInFastThrow -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UnlockExperimentalVMOptions -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC
## Young GC(以下同,略去详细内容)2021-01-08T04:12:09.331+0800: 1172604.919: [GC pause (G1 Evacuation Pause) (young), 0.0184242 secs] [Parallel Time: 15.1 ms, GC Workers: 4] [GC Worker Start (ms): Min: 1172604919.7, Avg: 1172604919.8, Max: 1172604919.8, Diff: 0.1] [Ext Root Scanning (ms): Min: 1.4, Avg: 1.7, Max: 2.6, Diff: 1.2, Sum: 6.9] [Update RS (ms): Min: 6.8, Avg: 7.4, Max: 7.8, Diff: 1.0, Sum: 29.8] [Processed Buffers: Min: 11, Avg: 18.2, Max: 27, Diff: 16, Sum: 73] [Scan RS (ms): Min: 0.4, Avg: 0.6, Max: 0.6, Diff: 0.2, Sum: 2.2] [Code Root Scanning (ms): Min: 0.0, Avg: 0.1, Max: 0.1, Diff: 0.1, Sum: 0.3] [Object Copy (ms): Min: 4.9, Avg: 5.0, Max: 5.1, Diff: 0.2, Sum: 19.9] [Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0] [Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 4] [GC Worker Other (ms): Min: 0.1, Avg: 0.1, Max: 0.1, Diff: 0.1, Sum: 0.4] [GC Worker Total (ms): Min: 14.8, Avg: 14.9, Max: 15.0, Diff: 0.2, Sum: 59.5] [GC Worker End (ms): Min: 1172604934.6, Avg: 1172604934.6, Max: 1172604934.7, Diff: 0.1] [Code Root Fixup: 0.0 ms] [Code Root Purge: 0.0 ms] [Clear CT: 0.5 ms] [Other: 2.8 ms] [Choose CSet: 0.0 ms] [Ref Proc: 0.3 ms] [Ref Enq: 0.0 ms] [Redirty Cards: 0.1 ms] [Humongous Register: 0.2 ms] [Humongous Reclaim: 0.0 ms] [Free CSet: 1.9 ms] [Eden: 2498.0M(2498.0M)->0.0B(2496.0M) Survivors: 6144.0K->6144.0K Heap: 5011.5M(5576.0M)->2513.8M(5576.0M)][Times: user=0.06 sys=0.00, real=0.02 secs] ## 初始标记 initial-mark2021-01-08T04:12:18.958+0800: 1172614.546: [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0199455 secs] ### ...... [Eden: 2496.0M(2496.0M)->0.0B(2492.0M) Survivors: 6144.0K->8192.0K Heap: 5009.8M(5576.0M)->2515.0M(5576.0M)][Times: user=0.05 sys=0.02, real=0.02 secs] ## 并发根节点扫描2021-01-08T04:12:18.979+0800: 1172614.567: [GC concurrent-root-region-scan-start]2021-01-08T04:12:19.004+0800: 1172614.592: [GC concurrent-root-region-scan-end, 0.0256504 secs]## 并发标记2021-01-08T04:12:19.004+0800: 1172614.592: [GC concurrent-mark-start]2021-01-08T04:12:19.214+0800: 1172614.802: [GC concurrent-mark-end, 0.2101424 secs]## 重新标记2021-01-08T04:12:19.215+0800: 1172614.803: [GC remark 2021-01-08T04:12:19.215+0800: 1172614.803: [Finalize Marking, 0.0003026 secs] 2021-01-08T04:12:19.215+0800: 1172614.803: [GC ref-proc, 0.7285039 secs] 2021-01-08T04:12:19.944+0800: 1172615.532: [Unloading, 0.0301928 secs], 0.7619789 secs][Times: user=0.95 sys=0.02, real=0.77 secs] ## 清理阶段2021-01-08T04:12:19.978+0800: 1172615.566: [GC cleanup 2575M->2567M(5576M), 0.0076275 secs][Times: user=0.00 sys=0.00, real=0.01 secs] 2021-01-08T04:12:19.986+0800: 1172615.574: [GC concurrent-cleanup-start]2021-01-08T04:12:19.986+0800: 1172615.574: [GC concurrent-cleanup-end, 0.0000396 secs]## 空间收集阶段的 young gc2021-01-08T04:12:28.168+0800: 1172623.756: [GC pause (G1 Evacuation Pause) (young), 0.0249811 secs] ### ...... [Eden: 2492.0M(2492.0M)->0.0B(1110.0M) Survivors: 8192.0K->4096.0K Heap: 4999.0M(5576.0M)->2504.2M(5576.0M)][Times: user=0.06 sys=0.03, real=0.02 secs] ## 空间收集阶段的 young gc(mixed)2021-01-08T04:12:31.149+0800: 1172626.737: [GC pause (G1 Evacuation Pause) (mixed), 0.0437074 secs] ### ...... [Eden: 1110.0M(1110.0M)->0.0B(1108.0M) Survivors: 4096.0K->6144.0K Heap: 3614.2M(5576.0M)->2206.5M(5576.0M)][Times: user=0.10 sys=0.04, real=0.04 secs] ## 空间收集阶段的 young gc(mixed)2021-01-08T04:12:34.734+0800: 1172630.322: [GC pause (G1 Evacuation Pause) (mixed), 0.0397893 secs] ### ...... [Eden: 1108.0M(1108.0M)->0.0B(1108.0M) Survivors: 6144.0K->6144.0K Heap: 3314.5M(5576.0M)->1916.7M(5576.0M)][Times: user=0.10 sys=0.04, real=0.04 secs] ## 空间收集阶段的 young gc(mixed)2021-01-08T04:12:39.836+0800: 1172635.424: [GC pause (G1 Evacuation Pause) (mixed), 0.0539989 secs] ### ...... [Eden: 1108.0M(1108.0M)->0.0B(1110.0M) Survivors: 6144.0K->4096.0K Heap: 3024.7M(5576.0M)->1536.4M(5576.0M)][Times: user=0.13 sys=0.05, real=0.05 secs]
- 案例二
## 大对象收集[GC pause (G1 Humongous Allocation) (young), 0.0022191 secs] [Parallel Time: 1.3 ms, GC Workers: 4] [GC Worker Start (ms): Min: 909912.8, Avg: 909913.1, Max: 909913.9, Diff: 1.1] [Ext Root Scanning (ms): Min: 0.0, Avg: 0.3, Max: 0.4, Diff: 0.4, Sum: 1.1] [Update RS (ms): Min: 0.0, Avg: 0.1, Max: 0.3, Diff: 0.3, Sum: 0.4] [Processed Buffers: Min: 0, Avg: 2.2, Max: 3, Diff: 3, Sum: 9] [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0] [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0] [Object Copy (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.1] [Termination (ms): Min: 0.0, Avg: 0.5, Max: 0.7, Diff: 0.7, Sum: 1.8] [Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 4] [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1] [GC Worker Total (ms): Min: 0.0, Avg: 0.9, Max: 1.2, Diff: 1.2, Sum: 3.5] [GC Worker End (ms): Min: 909914.0, Avg: 909914.0, Max: 909914.1, Diff: 0.1] [Code Root Fixup: 0.0 ms] [Code Root Purge: 0.0 ms] [Clear CT: 0.0 ms] [Other: 0.9 ms] [Choose CSet: 0.0 ms] [Ref Proc: 0.8 ms] [Ref Enq: 0.0 ms] [Redirty Cards: 0.1 ms] [Humongous Register: 0.0 ms] [Humongous Reclaim: 0.0 ms] [Free CSet: 0.0 ms] [Eden: 0.0B(2048.0K)->0.0B(2048.0K) Survivors: 0.0B->0.0B Heap: 38.1M(50.0M)->38.1M(50.0M)][Times: user=0.00 sys=0.01, real=0.00 secs] ## Full GC[Full GC (Allocation Failure) 38M->37M(50M), 0.0419625 secs] [Eden: 0.0B(2048.0K)->0.0B(2048.0K) Survivors: 0.0B->0.0B Heap: 38.1M(50.0M)->37.9M(50.0M)], [Metaspace: 30407K->30407K(1077248K)][Times: user=0.05 sys=0.00, real=0.04 secs] [Full GC (Allocation Failure) 37M->37M(50M), 0.0346627 secs] [Eden: 0.0B(2048.0K)->0.0B(2048.0K) Survivors: 0.0B->0.0B Heap: 37.9M(50.0M)->37.9M(50.0M)], [Metaspace: 30407K->30407K(1077248K)][Times: user=0.05 sys=0.00, real=0.04 secs]
低延迟垃圾收集器
- ZGC 收集器:JDK11 中推出的一款低延迟垃圾回收器,适用于大内存低延迟服务的内存管理和回收,SPECjbb 2015 基准测试,在 128G 的大堆下,最大停顿时间才 1.68 ms,停顿时间远胜于 G1 和 CMS。
- Shenandoah 收集器:由 Red Hat 的一个团队负责开发,与 G1 类似,基于 Region 设计的垃圾收集器,但不需要 Remember Set 或者 Card Table 来记录跨 Region 引用,停顿时间和堆的大小没有任何关系。停顿时间与 ZGC 接近。
常用垃圾收集器公共参数
以下两个命令结合起来可以大致推敲 JVM 默认参数:
java -XX:+PrintFlagsInitial ${pid} jinfo ${pid}
以下列举常用的一些公共参数:
参数 参数含义 默认值 -Xms -Xmx -Xmn 指定堆启动内存、堆最大内存、年轻代内存。比如 -Xmx5g 表示堆最大内存为5g。 -XX:ErrorFile=file 指定 Fatal Error日志文件位置,比如:./java_error_%p.log -XX:+HeapDumpOnOutOfMemoryError 指示 JVM 发生 OutOfMemory 的时候输出 dump 文件 -XX:-OmitStackTraceInFastThrow 该参数禁用 OmitStackTraceInFastThrow。OmitStackTraceInFastThrow 默认开启,指示 hotspot 使用fast throw来优化这个抛出异常的地方,直接抛出一个事先分配好的、类型匹配的对象,这个对象的message和stack trace都被清空。所以开启OmitStackTraceInFastThrow不利于排查问题。 -XX:+PrintGC 指示输出简要GC日志 -XX:+PrintGCDetails 指示输出详细GC日志 -XX:+PrintGCApplicationStoppedTime 指示打印STW时间 -XX:+PrintGCDateStamps 指示输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800) -XX:+PrintGCTimeStamps 该参数指示输出GC的时间戳(以JVM启动到当期的总时长的时间戳形式) -XX:+UseCompressedClassPointers 该参数指示压缩kclass指针大小 -XX:+UseCompressedOops 该参数指示进行指针压缩(包含kclass指针和对象指针) -Xloggc:${GC_LOG_PATH} 该参数指示输出GC日志到文件 -XX:SurvivorRatio=8 该参数设置的是Eden区与每一个Survivor区的比值,可以反推出占新生代的比值,Eden为8, 两个Survivor为1, Eden占新生代的4/5, 每个Survivor占1/10,两个占1/5 默认8 -XX:MetaspaceSize=64m-XX:MaxMetaspaceSize=128M 该参数指定元数据空间初始扩容阈值为64m,最大扩容空间为128M 默认值无穷大