JVM 启动参数
这篇讲 JDK 8、JDK 17、JDK 21 常用的 JVM 启动参数。分门别类,标明作用,拿来就能用。
1. 参数类型说明
JVM 参数分三种格式:
| 格式 | 说明 | 示例 |
|---|---|---|
-XX:+选项 | 开启某功能 | -XX:+UseG1GC |
-XX:-选项 | 关闭某功能 | -XX:-UseAdaptiveSizePolicy |
-XX:选项=值 | 设置某个值 | -XX:MaxGCPauseMillis=200 |
2. 通用参数(所有版本都能用)
2.1 内存设置
bash
# 堆内存大小
-Xms4g # 初始堆大小,建议和 Xmx 一样,避免动态扩容
-Xmx4g # 最大堆大小
# 新生代大小
-Xmn1g # 新生代大小(Eden + S0 + S1)
# 元空间(JDK8+ 替代永久代)
-XX:MetaspaceSize=256m # 初始元空间大小
-XX:MaxMetaspaceSize=512m # 最大元空间大小
# 栈大小
-Xss512k # 每个线程的栈大小,默认 1M内存配置建议:
| 场景 | Xms/Xmx | 说明 |
|---|---|---|
| 小应用 | 512m-1g | 微服务、小工具 |
| 中型应用 | 2g-4g | 普通 Web 应用 |
| 大型应用 | 4g-8g | 高并发服务 |
| 巨型应用 | 8g+ | 数据处理、缓存 |
💡 黄金法则:
-Xms和-Xmx设成一样,避免运行时内存抖动。
2.2 GC 日志(生产必配)
JDK 8 写法
bash
-XX:+PrintGCDetails # 打印 GC 详情
-XX:+PrintGCDateStamps # 打印日期时间戳(2024-01-17T10:30:00)
-XX:+PrintGCTimeStamps # 打印 JVM 启动后的秒数
-XX:+PrintGCApplicationStoppedTime # 打印 STW 停顿时间
-Xloggc:/logs/gc-%t.log # 输出文件(%t = 启动时间戳)
-XX:+UseGCLogFileRotation # 开启日志分卷
-XX:NumberOfGCLogFiles=10 # 保留 10 个日志文件
-XX:GCLogFileSize=50M # 每个文件最大 50MB参数说明:
| 参数 | 作用 |
|---|---|
%t | 文件名带启动时间戳,如 gc-2024-01-17_10-30-00.log |
UseGCLogFileRotation | 开启日志滚动,防止单文件过大 |
NumberOfGCLogFiles | 保留的日志文件数量 |
GCLogFileSize | 单个日志文件大小上限 |
JDK 9+ 统一写法
bash
# 基础版
-Xlog:gc*:file=/logs/gc.log:time,uptime,level,tags
# 完整版(带分卷)
-Xlog:gc*:file=/logs/gc-%t.log:time,uptime,level,tags:filecount=10,filesize=50m参数解析:
-Xlog:gc*:file=/logs/gc-%t.log:time,uptime,level,tags:filecount=10,filesize=50m
│ │ │ │
│ │ │ └─ 分卷设置
│ │ └─ 日志格式(时间、运行时长、级别、标签)
│ └─ 输出文件(%t = 启动时间戳)
└─ 打印所有 GC 相关日志2.3 OOM 时导出堆转储
bash
-XX:+HeapDumpOnOutOfMemoryError # OOM 时自动导出 dump
-XX:HeapDumpPath=/path/to/dump.hprof # dump 文件路径作用:程序 OOM 崩溃时,自动保存内存快照,方便事后分析。生产必加!
3. JDK 8 常用参数
JDK 8 默认用 Parallel GC(吞吐量优先)。
3.1 选择垃圾收集器
bash
# Parallel GC(默认,吞吐量优先)
-XX:+UseParallelGC
# CMS(低延迟,已废弃,但 JDK8 还能用)
-XX:+UseConcMarkSweepGC
# G1(推荐,平衡吞吐和延迟)
-XX:+UseG1GC3.2 G1 相关参数(JDK 8 推荐用 G1)
bash
-XX:+UseG1GC # 启用 G1
-XX:MaxGCPauseMillis=200 # 目标最大 GC 停顿时间(毫秒)
-XX:G1HeapRegionSize=16m # Region 大小(1-32M,必须是 2 的幂)
-XX:InitiatingHeapOccupancyPercent=45 # 堆使用率达到多少触发并发 GC3.3 JDK 8 生产环境模板
bash
java \
-Xms4g -Xmx4g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/dump.hprof \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-XX:+PrintGCTimeStamps \
-Xloggc:/logs/gc-%t.log \
-XX:+UseGCLogFileRotation \
-XX:NumberOfGCLogFiles=10 \
-XX:GCLogFileSize=50M \
-jar app.jar4. JDK 17 常用参数
JDK 17 是 LTS 版本,默认用 G1 GC。
4.1 垃圾收集器选择
bash
# G1(默认)
-XX:+UseG1GC
# ZGC(超低延迟,推荐大堆)
-XX:+UseZGC
# Shenandoah(另一个低延迟收集器)
-XX:+UseShenandoahGC4.2 G1 调优参数
bash
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200 # 目标停顿时间
-XX:G1HeapRegionSize=16m # Region 大小
-XX:G1NewSizePercent=20 # 新生代最小占比
-XX:G1MaxNewSizePercent=40 # 新生代最大占比
-XX:G1ReservePercent=10 # 保留内存百分比4.3 ZGC 参数(JDK 17 推荐)
| 特点 | 说明 |
|---|---|
| 超低延迟 | 停顿时间 < 1ms |
| 支持大堆 | 可达 16TB |
| 适用场景 | 对延迟敏感的应用 |
bash
-XX:+UseZGC
-XX:SoftMaxHeapSize=4g # 软性堆上限
-XX:ZCollectionInterval=120 # ZGC 触发间隔(秒)4.4 JDK 17 生产环境模板
G1 版本:
bash
java \
-Xms4g -Xmx4g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/dump.hprof \
-Xlog:gc*:file=/logs/gc.log:time,uptime,level,tags \
-jar app.jarZGC 版本(低延迟场景):
bash
java \
-Xms8g -Xmx8g \
-XX:+UseZGC \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/dump.hprof \
-Xlog:gc*:file=/logs/gc.log:time,uptime,level,tags \
-jar app.jar5. JDK 21 常用参数
JDK 21 是最新 LTS,默认用 G1 GC,ZGC 已成熟。
5.1 垃圾收集器选择
bash
# G1(默认)
-XX:+UseG1GC
# ZGC(推荐,分代版)
-XX:+UseZGC
-XX:+ZGenerational # 开启分代 ZGC(JDK 21 新特性)
# Shenandoah
-XX:+UseShenandoahGC5.2 分代 ZGC(JDK 21 新特性)
JDK 21 的 ZGC 支持分代,性能更好:
bash
-XX:+UseZGC
-XX:+ZGenerational # 开启分代模式分代 ZGC 的好处:
- 更高效地回收短命对象
- 减少内存占用
- 进一步降低延迟
5.3 虚拟线程相关
JDK 21 引入虚拟线程,相关参数:
bash
# 虚拟线程载体线程数(默认 CPU 核心数)
-Djdk.virtualThreadScheduler.parallelism=16
# Pin 事件 Dump(调试用)
-Djdk.tracePinnedThreads=full5.4 JDK 21 生产环境模板
G1 版本:
bash
java \
-Xms4g -Xmx4g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/dump.hprof \
-Xlog:gc*:file=/logs/gc.log:time,uptime,level,tags \
-jar app.jar分代 ZGC 版本(推荐):
bash
java \
-Xms8g -Xmx8g \
-XX:+UseZGC \
-XX:+ZGenerational \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/dump.hprof \
-Xlog:gc*:file=/logs/gc.log:time,uptime,level,tags \
-jar app.jar6. 各版本垃圾收集器对比
| 收集器 | JDK 8 | JDK 17 | JDK 21 | 特点 |
|---|---|---|---|---|
| Serial | ✅ | ✅ | ✅ | 单线程,客户端模式 |
| Parallel | ✅ 默认 | ✅ | ✅ | 吞吐量优先 |
| CMS | ✅ | ❌ 移除 | ❌ 移除 | 低延迟(已废弃) |
| G1 | ✅ | ✅ 默认 | ✅ 默认 | 平衡吞吐和延迟 |
| ZGC | ❌ | ✅ | ✅ | 超低延迟 < 1ms |
| Shenandoah | ❌ | ✅ | ✅ | 低延迟 |
7. 快速选型指南
| 场景 | 推荐收集器 | 参数 |
|---|---|---|
| 普通 Web 应用 | G1 | -XX:+UseG1GC |
| 高吞吐批处理 | Parallel | -XX:+UseParallelGC |
| 低延迟 API 服务 | ZGC | -XX:+UseZGC |
| 大堆(8G+)低延迟 | ZGC | -XX:+UseZGC -XX:+ZGenerational |
| 小堆(<2G) | G1 或 Parallel | -XX:+UseG1GC |
8. Kubernetes / 容器环境
8.1 容器感知参数
| 参数 | 作用 | 版本支持 |
|---|---|---|
UseContainerSupport | 让 JVM 识别容器的 CPU 和内存限制 | JDK 8u191+、JDK 10+ |
MaxRAMPercentage | 堆内存占容器内存的百分比 | JDK 8u191+ |
InitialRAMPercentage | 初始堆内存占比 | JDK 8u191+ |
💡 重要:容器感知功能最早在 JDK 10 引入,后来回移(backport)到了 JDK 8u191+,所以 JDK 8 用户升级到 8u191 以上即可使用。
bash
# 开启容器感知(JDK 10+ 默认开启,JDK 8u191+ 需显式开启)
-XX:+UseContainerSupport
# 容器内存的使用比例(默认 25%,建议调高)
-XX:MaxRAMPercentage=75.0
# 初始内存也用百分比
-XX:InitialRAMPercentage=75.0
# 限制 JVM 可见的 CPU 核心数(可选)
-XX:ActiveProcessorCount=48.2 为什么用百分比而不是固定值?
| 方式 | 优点 | 缺点 |
|---|---|---|
-Xmx4g 固定值 | 精确控制 | 容器 limit 改了还得改 JVM 参数 |
MaxRAMPercentage 百分比 | 自动适配容器限制 | 稍微没那么精确 |
推荐:容器环境用百分比,更灵活。
8.3 K8s 容器模板
JDK 8u191+ 版本:
bash
java \
-XX:+UseContainerSupport \
-XX:InitialRAMPercentage=75.0 \
-XX:MaxRAMPercentage=75.0 \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/dump.hprof \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-Xloggc:/logs/gc-%t.log \
-XX:+UseGCLogFileRotation \
-XX:NumberOfGCLogFiles=5 \
-XX:GCLogFileSize=20M \
-jar app.jarJDK 17/21 版本:
bash
java \
-XX:InitialRAMPercentage=75.0 \
-XX:MaxRAMPercentage=75.0 \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/logs/dump.hprof \
-Xlog:gc*:file=/logs/gc-%t.log:time,uptime,level,tags:filecount=5,filesize=20m \
-jar app.jar💡 JDK 10+ 默认开启
UseContainerSupport,无需显式指定。
8.4 常见问题
Q:为什么设置 75% 而不是 100%?
A:因为 JVM 的内存不只是堆,还包括:
- 元空间(Metaspace)
- 线程栈
- JIT 编译缓存
- 直接内存(DirectByteBuffer)
如果堆设 100%,这些额外内存会超出容器限制,导致被 OOM Killer 杀掉。
Q:容器 limit 2G,实际能用多少堆?
A:2G × 75% = 1.5G 左右的堆,其余留给非堆内存。