TL;DR
- 场景:RocketMQ 4.5.1 在 JDK9+ 启动被「废弃/移除的 JVM 参数」和「类路径未加载 lib」卡住。
- 结论:删 CMS/ParNew 与 java.ext.dirs,GC 日志切 -Xlog,CLASSPATH 补 ${BASE_DIR}/lib/*。
- 产出:runserver/runbroker/tools 三处最小改动清单 + 版本矩阵 + 错误速查卡。

版本矩阵
| 项目 | 说明 |
|---|---|
| RocketMQ 4.5.1 | 文中下载与脚本修改均以4.5.1的bin包路径结构为前提(conf、lib、bin)。 |
| JDK 8 | 不属于本文"必须改脚本"的目标区间;旧参数体系更容易"还能跑",但与本文JDK9+统一日志改法不同。 |
| JDK 9--17 | 本文修改点(删CMS/ParNew、删java.ext.dirs、-Xlog、补lib/*)面向该区间的典型兼容面。 |
| JDK 18+ | 文中未给出该区间的明确验证信号;仍按JDK9+逻辑处理,但不对"零差异可用"做一致性承诺。 |
| Linux(通用) | 路径与命令按常见发行版shell环境编写;/etc/profile、/dev/shm、~/logs写法依赖标准目录约定。 |
RocketMQ 环境搭建
软件下载

我们先进入到目录,然后对软件进行下载:
shell
cd /opt/software
接着我们通过 wget 进行下载:
shell
wget https://archive.apache.org/dist/rocketmq/4.5.1/rocketmq-all-4.5.1-bin-release.zip
对应内容如下所示:

解压移动
shell
unzip rocketmq-all-4.5.1-bin-release.zip
mv rocketmq-all-4.5.1-bin-release ../server/rocketmq
对应的结果如下所示:

修改脚本
- bin/runserver.sh
- bin/runbroker.sh
- bin/tools.sh
我们首先进入配置目录
shell
cd /opt/server/rocketmq
runserver
shell
vim bin/runserver.sh
根据下面的要求删除对应的内容(后续会解释为什么要删除):
删除
- UseCMSCompactAtFullCollection
- UseParNewGC
- UseConcMarkSweepGC
修改内存
shell
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=64mm -XX:MaxMetaspaceSize=160mm"
修改gc配置
shell
-Xloggc 修改为 -Xlog:gc
整体修改完:
shell
#===========================================================================================
# JVM Configuration
#===========================================================================================
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=160m"
JAVA_OPT="${JAVA_OPT} -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8"
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xlog:gc:/dev/shm/rmq_srv_gc.log -XX:+PrintGCDetails"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"
#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}"
classpath 这里需要补一个:
shell
# 原来是
export CLASSPATH=".:${BASE_DIR}/conf:CLASSPATH
# 补充完
export CLASSPATH=".:${BASE_DIR}/conf:${BASE_DIR}/lib/*"
基本内容如下所示了:

broker
shell
vim bin/runbroker.sh
修改一下JVM的参数:
shell
-Xms256m -Xmx256m -Xmn128m
删除
- PrintGCDateStamps
- PrintGCApplicationStoppedTime
- PrintAdaptiveSizePolicy
- UseGCLogFileRotation
- NumberOfGCLogFiles=5
- GCLogFileSize=30m
删除:
shell
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
整体上就是删除了一大段:
shell
#===========================================================================================
# JVM Configuration
#===========================================================================================
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g -Xmn4g"
JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0"JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails"
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}"
classpath 这里需要补一个:
shell
# 原来是
export CLASSPATH=".:${BASE_DIR}/conf:CLASSPATH
# 补充完
export CLASSPATH=".:${BASE_DIR}/conf:${BASE_DIR}/lib/*"
整体如下:

tools
shell
vim bin/tools.sh
删除:
shell
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${BASE_DIR}/lib:${JAVA_HOME}/jre/lib/ext"
classpath 这里需要补一个:
shell
# 原来是
export CLASSPATH=".:${BASE_DIR}/conf:CLASSPATH
# 补充完
export CLASSPATH=".:${BASE_DIR}/conf:${BASE_DIR}/lib/*"
整体结果如下:

针对修改的解释
这些改动的核心动机只有一个:让 RocketMQ 的启动脚本在 JDK9+(尤其 JDK14/15+)不再因为"过时/被移除的 JVM 参数"而告警或直接启动失败,同时把 GC 日志切到 JDK9 引入的统一日志体系。
runserver:删除 CMS/ParNew 相关参数 + 换 GC 日志体系 + 改内存
删除 UseCMSCompactAtFullCollection / UseParNewGC / UseConcMarkSweepGC
- UseConcMarkSweepGC(CMS)在 JDK9 就被标记为 deprecated,后续版本彻底移除;继续带着该参数会从"警告"变成"直接报错退出"。
- UseParNewGC 是 CMS 时代常见的年轻代收集器搭配项;当 CMS 被移除后,这类 仅对 CMS 有意义的参数会被废弃/作废。
- UseCMSCompactAtFullCollection 是 CMS 体系内的 Full GC 压缩控制项;同样属于 CMS 专属参数,CMS 消失后它也没有语义价值。
- JDK9 起默认 GC 已经切换到 G1("让 G1 成为默认"是 JDK9 的方向之一),所以很多人直接把 CMS/ParNew 参数整段删掉,避免版本兼容问题。
-Xloggc 改为 -Xlog:gc:JDK9 引入 Unified JVM Logging(统一日志框架),GC 日志也随之迁移到 -Xlog 体系;老式的 -Xloggc 与一堆 -XX:+PrintGC... 组合逐步被替代。
修改内存:-Xms/-Xmx/-Xmn/MetaspaceSize/MaxMetaspaceSize
- -Xms/-Xmx:分别是堆初始/最大;设为相同通常是为了避免运行时扩容带来的抖动(脚本层面追求"固定堆")。
- -Xmn:年轻代大小(影响 minor GC 频率与停顿形态)。
- MetaspaceSize/MaxMetaspaceSize:类元数据区阈值与上限;控制类加载相关的内存占用与触发元空间回收的节奏。
broker:删掉一批 GC 日志旧参数(因为统一日志体系不吃这套了)
- PrintGCDateStamps
- PrintGCApplicationStoppedTime
- PrintAdaptiveSizePolicy
- UseGCLogFileRotation
- NumberOfGCLogFiles
- GCLogFileSize
本质都属于 JDK8 及以前的"老 GC 日志开关 + 老日志轮转方式"。
JDK9+ 统一切到 -Xlog 后,这些要么被忽略、要么报 deprecated/obsolete,最终目的是把配置收敛到类似下面的能力集合:
- 时间戳/停顿/更细粒度标签(由 -Xlog:...:time,uptime,tags,level 之类表达)
- 文件输出与轮转(在 -Xlog 的 file 语法里完成,而不是 UseGCLogFileRotation/GCLogFileSize/... 这一套老参数)
tools:删除 -Djava.ext.dirs=...(JDK9 起扩展机制被移除)
-Djava.ext.dirs 依赖的是 JRE 的 extension classloader 机制(把 jar 放到 lib/ext 或用 java.ext.dirs 注入)。这个机制在 JDK9 因模块化运行时(JPMS)被移除;只要设置该属性,启动器就可能直接失败。
因此把 tools.sh 里这行删掉,是为了避免在 JDK9+ 上"脚本先天不兼容"的硬错误。
环境变量
配置RocketMQ的环境变量,方便我们后续进行服务启动:
shell
vim /etc/profile
shell
# RocketMQ 环境变量
export ROCKET_HOME="/opt/server/rocketmq"
export PATH="${ROCKET_HOME}/bin:$PATH"
写入的内容如下所示:

最后记得刷新
shell
source /etc/profile
启动服务
NameServer
shell
mqnamesrv

查看当前的服务日志:
shell
tail -f ~/logs/rocketmqlogs/namesrv.log
Broker
启动服务:
shell
mqbroker -n 0.0.0.0:9876
启动结果如下所示:

查看日志:
shell
tail -f ~/logs/rocketmqlogs/broker.log
服务测试
发送消息
设置环境变量
shell
export NAMESRV_ADDR=0.0.0.0:9876
使用官方提供的Demo:
shell
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
执行结果如下所示:

接收消息
设置环境变量
shell
export NAMESRV_ADDR=0.0.0.0:9876
使用官方提供的Demo:
shell
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
执行结果如下所示:

关闭RocketMQ
shell
mqshutdown namesrv
mqshutdown broker
错误速查
| 症状 | 根因定位 | 修复 |
|---|---|---|
| Unrecognized VM option 'UseConcMarkSweepGC' 或直接退出 | JDK9+ 移除/废弃 CMS/ParNew 体系参数 | java -version;启动日志首屏 JVM options 从 runserver.sh 删除 UseConcMarkSweepGC/UseParNewGC/UseCMSCompactAtFullCollection(保持 G1 或默认) |
| GC 日志参数告警/不生效(-Xloggc、PrintGCDateStamps 等) | JDK9+ 统一日志体系迁移到 -Xlog,旧开关逐步废弃 | 搜索脚本中的 -Xloggc、PrintGC*、UseGCLogFileRotation 将 -Xloggc 改为 -Xlog:gc:...;在 broker 脚本删除老式 GC 日志与轮转参数 |
| Error: Could not find or load main class org.apache.rocketmq.namesrv.NamesrvStartup | CLASSPATH 未包含 ${BASE_DIR}/lib/*(或脚本中 CLASSPATH 拼错为字面量 CLASSPATH)导致核心类不在类路径 | echo $CLASSPATH;bash -x mqnamesrv 看最终 -cp 将 export CLASSPATH=".:${BASE_DIR}/conf:${BASE_DIR}/lib/*" 固化到脚本;避免 ...:CLASSPATH 这种字面量拼接 |
| tools.sh 执行 Demo 报 ClassNotFound / 直接启动失败 | -Djava.ext.dirs=... 依赖 JRE ext 机制,JDK9 起移除 | 在 tools.sh 搜 java.ext.dirs;观察 JVM 启动报错 删除 JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=...";用 CLASSPATH=conf + lib/* 承载依赖 |
| JVM 启动时报 Invalid -XX:MetaspaceSize=... 或参数解析失败 | 参数单位/拼写错误(如 64mm) | 启动日志中的 "Improperly specified VM option" 把 -XX:MetaspaceSize=64mm 修正为 -XX:MetaspaceSize=64m(同理检查 MaxMetaspaceSize) |
| 环境变量设置后仍找不到命令 | 脚本引用目录不一致变量名不一致(如 ROCKETMQ_HOME vs ROCKET_HOME)导致脚本/命令路径判断偏离 | envgrep ROCKET;检查 bin 脚本对 HOME 变量的读取 |
其他系列
🚀 AI篇持续更新中(长期更新)
AI炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究 ,持续打造实用AI工具指南!
AI研究-132 Java 生态前沿 2025:Spring、Quarkus、GraalVM、CRaC 与云原生落地
🔗 AI模块直达链接
💻 Java篇持续更新中(长期更新)
Java-207 RabbitMQ Direct 交换器路由:RoutingKey 精确匹配、队列多绑定与日志分流实战
MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务已完结,Dubbo已完结,MySQL已完结,MongoDB已完结,Neo4j已完结,FastDFS 已完结,OSS已完结,GuavaCache已完结,EVCache已完结,RabbitMQ正在更新... 深入浅出助你打牢基础!
🔗 Java模块直达链接
📊 大数据板块已完成多项干货更新(300篇):
包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解
🔗 大数据模块直达链接