共计 11959 个字符,预计需要花费 30 分钟才能阅读完成。
引言
继 [[【RocketMq】NameServ 启动脚本剖析(Ver4.9.4)]] 之后又来看看 Broker 的脚本。总体上来看大差不差,以浏览外围的配置局部调优为主。
mqbroker
#!/bin/sh | |
if [-z "$ROCKETMQ_HOME"] ; then | |
## resolve links - $0 may be a link to maven's home | |
PRG="$0" | |
# need this for relative symlinks | |
while [-h "$PRG"] ; do | |
ls=`ls -ld "$PRG"` | |
link=`expr "$ls" : '.*-> \(.*\)$'` | |
if expr "$link" : '/.*' > /dev/null; then | |
PRG="$link" | |
else | |
PRG="`dirname"$PRG"`/$link" | |
fi | |
done | |
saveddir=`pwd` | |
ROCKETMQ_HOME=`dirname "$PRG"`/.. | |
# make it fully qualified | |
ROCKETMQ_HOME=`cd "$ROCKETMQ_HOME" && pwd` | |
cd "$saveddir" | |
fi | |
export ROCKETMQ_HOME | |
sh ${ROCKETMQ_HOME}/bin/runbroker.sh org.apache.rocketmq.broker.BrokerStartup $@ |
后面的一大段脚本的最终目标就是获取 ROCKETMQ_HOME
的变量。
咱们关注最初一个脚本,这里调用了 runbroker.sh
的脚本:
sh ${ROCKETMQ_HOME}/bin/runbroker.sh org.apache.rocketmq.broker.BrokerStartup $@
runbroker.sh
runbroker.sh
的脚本尽管内容很多,然而大部分和之前剖析 NameServ 的启动内容是重合的,这里间接跳过其余函数判断,只关注 JVM 的参数设置局部。
#!/bin/sh | |
#=========================================================================================== | |
# Java Environment Setting | |
#=========================================================================================== | |
error_exit () | |
{echo "ERROR: $1 !!" exit 1} | |
[! -e "$JAVA_HOME/bin/java"] && JAVA_HOME=$HOME/jdk/java | |
[! -e "$JAVA_HOME/bin/java"] && JAVA_HOME=/usr/java | |
[! -e "$JAVA_HOME/bin/java"] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!" | |
export JAVA_HOME | |
export JAVA="$JAVA_HOME/bin/java" | |
export BASE_DIR=$(dirname $0)/.. | |
export CLASSPATH=.:${BASE_DIR}/conf:${BASE_DIR}/lib/*:${CLASSPATH} | |
#=========================================================================================== | |
# JVM Configuration | |
#=========================================================================================== | |
# The RAMDisk initializing size in MB on Darwin OS for gc-log | |
DIR_SIZE_IN_MB=600 | |
choose_gc_log_directory() | |
{ | |
case "`uname`" in | |
Darwin) | |
if [! -d "/Volumes/RAMDisk"]; then | |
# create ram disk on Darwin systems as gc-log directory | |
DEV=`hdiutil attach -nomount ram://$((2 * 1024 * DIR_SIZE_IN_MB))` > /dev/null | |
diskutil eraseVolume HFS+ RAMDisk ${DEV} > /dev/null | |
echo "Create RAMDisk /Volumes/RAMDisk for gc logging on Darwin OS." | |
fi | |
GC_LOG_DIR="/Volumes/RAMDisk" | |
;; | |
*) | |
# check if /dev/shm exists on other systems | |
if [-d "/dev/shm"]; then | |
GC_LOG_DIR="/dev/shm" | |
else | |
GC_LOG_DIR=${BASE_DIR} | |
fi | |
;; esac} | |
choose_gc_options() | |
{JAVA_MAJOR_VERSION=$("$JAVA" -version 2>&1 | head -1 | cut -d'"'-f2 | sed's/^1\.//'| cut -d'.' -f1) | |
if [-z "$JAVA_MAJOR_VERSION"] || ["$JAVA_MAJOR_VERSION" -lt "8"] ; then | |
JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 -XX:-UseParNewGC" else | |
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0" fi | |
if [-z "$JAVA_MAJOR_VERSION"] || ["$JAVA_MAJOR_VERSION" -lt "9"] ; then | |
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" | |
JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" else | |
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0" JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log:time,tags:filecount=5,filesize=30M" | |
fi | |
} | |
choose_gc_log_directory | |
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g"choose_gc_options | |
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"JAVA_OPT="${JAVA_OPT} -XX:+AlwaysPreTouch"JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=15g"JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking"#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n" | |
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}" | |
JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}" | |
numactl --interleave=all pwd > /dev/null 2>&1 | |
if [$? -eq 0] | |
then | |
if [-z "$RMQ_NUMA_NODE"] ; then | |
numactl --interleave=all $JAVA ${JAVA_OPT} $@ | |
else | |
numactl --cpunodebind=$RMQ_NUMA_NODE --membind=$RMQ_NUMA_NODE $JAVA ${JAVA_OPT} $@ | |
fi | |
else | |
$JAVA ${JAVA_OPT} $@ | |
fi |
choose_gc_options() 剖析
先来看如何抉择 GC 参数局部。
choose_gc_options() | |
{JAVA_MAJOR_VERSION=$("$JAVA" -version 2>&1 | head -1 | cut -d'"'-f2 | sed's/^1\.//'| cut -d'.' -f1) | |
if [-z "$JAVA_MAJOR_VERSION"] || ["$JAVA_MAJOR_VERSION" -lt "8"] ; | |
then | |
JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 -XX:-UseParNewGC" else | |
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0" | |
fi | |
if [-z "$JAVA_MAJOR_VERSION"] || ["$JAVA_MAJOR_VERSION" -lt "9"] ; then | |
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" | |
JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" | |
else | |
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0" | |
JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log:time,tags:filecount=5,filesize=30M" | |
fi | |
} |
粗略看去和 NameServ 的参数基本上没啥差异(难堪 ….),这里只好列举一些这些参数的作用了:
留神 Broker 对于小于 JDK8 的版本和小于 JDK9 的版本做了两种策略,这里的脚本其实是有点奇怪的,因为RocketMq 最低不是只反对 JDK8 么? 当然这样的脚本设置也不是不能够,只是没啥作用罢了。
因为怎么看怎么顺当,为了不便了解,集体调整了一下这个脚本的“实在用意”,针对 JDK8 和 JDK8 以下和 JDK8 以上三个分支判断:
- JDK8 以下用 CMS+ParNew 垃圾收集器经典组合
- G1 是在 JDK9 才成为默认垃圾收集器的,JDK8 须要手动设置应用 G1。须要留神这个版本 G1 是残血版本,Full Gc 是单线程的,JDK11 才被 Oracle 官网加上去。(顺带一提满血的 G1 从配置能够猜到是大量复用 CMS 的代码实现的)
- JDK8 之前的日志打印参数应用了 xloggc,JDK9 以及之后的版本用一个对立的打印参数
xlog
替换与之配合的附加参数,脚本洁净了很多。 - JDK 版本晋升能够看出官网在尽可能各方面简化垃圾收集器的参数管制,比方日志接口对立和简化。
choose_gc_options() | |
{JAVA_MAJOR_VERSION=$("$JAVA" -version 2>&1 | head -1 | cut -d'"'-f2 | sed's/^1\.//'| cut -d'.' -f1) | |
# 如果以后版本小于 JDK1.8,应用 CMS+ParNew 垃圾收集器组合和相干参数 | |
if [-z "$JAVA_MAJOR_VERSION"] || ["$JAVA_MAJOR_VERSION" -lt "8"] ; then | |
# CMS + ParNew 垃圾收集器 | |
# CMSInitiatingOccupancyFraction=70 示意当老年代达到 70% 时,触发 CMS 垃圾回收。# CMSParallelRemarkEnabled 老年代收集器指定为 CMS 的时候无效,在进行了 Full GC 时对老年代进行压缩整顿,解决掉内存碎片。# UseConcMarkSweepGC 应用 CMS 老年代收集器 | |
# SoftRefLRUPolicyMSPerMB 软援用不给任何的存活工夫,对于序列化或者反射的对象在垃圾回收的时候踊跃清理 | |
# CMSClassUnloadingEnabled 启用对 Perm 区启用类回收,避免 Perm 区内存垃圾对象堆满 | |
# -XX:SurvivorRatio=8 Eden 区域在新生代占比,Eden 占新生代的 8 /10,From 幸存区和 To 幸存区各占新生代的 1 /10 | |
# -XX:-UseParNewGC ParNew 新生代垃圾收集器 | |
JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 -XX:-UseParNewGC" | |
# 垃圾收集器日志存储配置 | |
# PrintGCApplicationStoppedTime 打印利用因为 GC 而产生的进展工夫 | |
# 这个参数的次要作用是能够在 JVM 运行的时候动静调整新生代的 Eden、From、To 三个区域的区域调配,计算根据是 GC 过程中统计的 **GC 工夫、吞吐量、内存占用量 **。# -verbose:gc 和 -XX:+PrintGCDetails 垃圾收集时的信息打印 打印开启,大部分时候会一起配置 | |
# PrintGCDateStamps 打印 GC 产生时的工夫戳,搭配 -XX:+PrintGCDetails 应用,不能够独立应用 | |
# PrintAdaptiveSizePolicy 动静调整 Eden From To 三个区域的大小,判断根据为 GC 工夫、吞吐量、内存占用量 | |
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" | |
# 给予 5 个 GC 日志文件,每个文件 30M,如果 5 个文件写满,则从第一个文件笼罩。JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" | |
# 如果以后版本等于 JDK 1.8 | |
else if ["$JAVA_MAJOR_VERSION" -eq "8"]; then | |
# PrintGCApplicationStoppedTime 打印利用因为 GC 而产生的进展工夫 | |
# 这个参数的次要作用是能够在 JVM 运行的时候动静调整新生代的 Eden、From、To 三个区域的区域调配,计算根据是 GC 过程中统计的 **GC 工夫、吞吐量、内存占用量 **。# -verbose:gc 和 -XX:+PrintGCDetails 垃圾收集时的信息打印 打印开启,大部分时候会一起配置 | |
# PrintGCDateStamps 打印 GC 产生时的工夫戳,搭配 -XX:+PrintGCDetails 应用,不能够独立应用 | |
# PrintAdaptiveSizePolicy 动静调整 Eden From To 三个区域的大小,判断根据为 GC 工夫、吞吐量、内存占用量 | |
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" | |
# 给予 5 个 GC 日志文件,每个文件 30M,如果 5 个文件写满,则从第一个文件笼罩。JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" | |
# 触发全局并发标记的老年代应用占比,默认值 45%。# UseG1GC G1 垃圾收集器 | |
# SoftRefLRUPolicyMSPerMB 软援用不给任何的存活工夫,对于序列化或者反射的对象在垃圾回收的时候踊跃清理。# G1HeapRegionSize 16M 一个 Region 的大小能够通过参数 `-XX:G1HeapRegionSize` 设定,取值范畴从 1M 到 32M,且是 2 的指数。如果不设定,那么 G1 会依据 Heap 大小主动决定。JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0" | |
fi | |
# 如果是 JDK 9 以及 JDK9 之后的版本 | |
else | |
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0" | |
# -Xlog 是 JDK9 对立日志参数,对于之前版本凌乱的 GC LOG 日志治理进行一波优化 | |
JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log:time,tags:filecount=5,filesize=30M" | |
fi | |
} |
如果一个参数调研那么文章会没完没了,咱们间接拆分三局部进行浏览。
JDK8 以下的版本(无用)
实践上来说没屁用的 GC 参数,因为 RocketMq 规定了最低反对的 JDK 版本为 JDK1.8。
if [-z "$JAVA_MAJOR_VERSION"] || ["$JAVA_MAJOR_VERSION" -lt "8"] ; then | |
# CMS + ParNew 垃圾收集器 | |
# CMSInitiatingOccupancyFraction=70 示意当老年代达到 70% 时,触发 CMS 垃圾回收。# CMSParallelRemarkEnabled 老年代收集器指定为 CMS 的时候无效,在进行了 Full GC 时对老年代进行压缩整顿,解决掉内存碎片。# UseConcMarkSweepGC 应用 CMS 老年代收集器 | |
# SoftRefLRUPolicyMSPerMB 软援用不给任何的存活工夫,对于序列化或者反射的对象在垃圾回收的时候踊跃清理 | |
# CMSClassUnloadingEnabled 启用对 Perm 区启用类回收,避免 Perm 区内存垃圾对象堆满 | |
# -XX:SurvivorRatio=8 Eden 区域在新生代占比,Eden 占新生代的 8 /10,From 幸存区和 To 幸存区各占新生代的 1 /10 | |
# -XX:-UseParNewGC ParNew 新生代垃圾收集器 | |
JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 -XX:-UseParNewGC" | |
# 垃圾收集器日志存储配置 | |
# PrintGCApplicationStoppedTime 打印利用因为 GC 而产生的进展工夫 | |
# 这个参数的次要作用是能够在 JVM 运行的时候动静调整新生代的 Eden、From、To 三个区域的区域调配,计算根据是 GC 过程中统计的 **GC 工夫、吞吐量、内存占用量 **。# -verbose:gc 和 -XX:+PrintGCDetails 垃圾收集时的信息打印 打印开启,大部分时候会一起配置 | |
# PrintGCDateStamps 打印 GC 产生时的工夫戳,搭配 -XX:+PrintGCDetails 应用,不能够独立应用 | |
# PrintAdaptiveSizePolicy 动静调整 Eden From To 三个区域的大小,判断根据为 GC 工夫、吞吐量、内存占用量 | |
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" | |
# 给予 5 个 GC 日志文件,每个文件 30M,如果 5 个文件写满,则从第一个文件笼罩。JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" |
JDK8 版本
从 JDK8 的版本开始,RocketMq 的垃圾收集器变更为 G1,对应的参数配置也是 G1 的配置。然而须要留神 -Xloggc
的配置文件利用了工夫戳进行格式化避免轮循反复笼罩的问题。其余参数曾经在 NameServ 的笔记中进行过剖析,集体把参数写入到命令上方不便查看
# 如果以后版本等于 JDK 1.8 | |
else if ["$JAVA_MAJOR_VERSION" -eq "8"]; then | |
# PrintGCApplicationStoppedTime 打印利用因为 GC 而产生的进展工夫 | |
# 这个参数的次要作用是能够在 JVM 运行的时候动静调整新生代的 Eden、From、To 三个区域的区域调配,计算根据是 GC 过程中统计的 **GC 工夫、吞吐量、内存占用量 **。# -verbose:gc 和 -XX:+PrintGCDetails 垃圾收集时的信息打印 打印开启,大部分时候会一起配置 | |
# PrintGCDateStamps 打印 GC 产生时的工夫戳,搭配 -XX:+PrintGCDetails 应用,不能够独立应用 | |
# PrintAdaptiveSizePolicy 动静调整 Eden From To 三个区域的大小,判断根据为 GC 工夫、吞吐量、内存占用量 | |
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy" | |
# 给予 5 个 GC 日志文件,每个文件 30M,如果 5 个文件写满,则从第一个文件笼罩。JAVA_OPT="${JAVA_OPT} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m" | |
# 触发全局并发标记的老年代应用占比,默认值 45%。# UseG1GC G1 垃圾收集器 | |
# SoftRefLRUPolicyMSPerMB 软援用不给任何的存活工夫,对于序列化或者反射的对象在垃圾回收的时候踊跃清理。JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0" | |
fi |
JDK9 及之后的版本
如果是之后的版本,则基本上的 GC 垃圾收集器和参数不变,然而须要留神 JDK9 之后因为 Xloggc 的参数被废除,用了 -xlog
的参数作为代替,这个起名的确比拟坑,因为和之前长的特地像。
# 如果是 JDK 9 以及 JDK9 之后的版本 | |
else | |
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0" | |
# -Xlog 是 JDK9 对立日志参数,对于之前版本凌乱的 GC LOG 日志治理进行一波优化 | |
JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${GC_LOG_DIR}/rmq_srv_gc_%p_%t.log:time,tags:filecount=5,filesize=30M" | |
fi |
Oracle 官网文档也解释了这几个 JDK8 以及之前的日志打印参数被废除。
https://docs.oracle.com/en/java/javase/11/jrockit-hotspot/logging.html#GUID-33074D03-B4F3-4D16-B9B6-8B0076661AAF
须要留神
因为日志参数打印属于 JVM 的领域,本节不做过多探讨。
总结
- JDK8 之前应用 Cms+ParNew,JDK8 以及之后的版本全副采纳 G1 垃圾收集器。
- NameServ 的启动脚本和 Broker 的相似,看懂任意一个就可以看懂另一个。
- Xlog 和 Xloggc 是比拟容易混同的中央,也是集体认为 Broker 启动脚本在不同版本判断启动参数理论最大的区别。
- 按照脚本的判断逻辑,上面的 JVM 参数在 JDK 9 及之后会呈现两次。
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0"
写在最初
从脚本格调能够看出和改写 NameServ.sh
的人是同一个编写,所以有很多大量重复性的内容都给省略了,具体的介绍都放到了 nameserv.sh
的脚本剖析当中。
通篇看下来集体不太了解为什么要针对 JDK8 以前的版本做 JVM 参数调优,或者这就是工程师编写的谨严之处吧,思考全面,值得学习。