Skip to content

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:+UseG1GC

3.2 G1 相关参数(JDK 8 推荐用 G1)

bash
-XX:+UseG1GC                          # 启用 G1
-XX:MaxGCPauseMillis=200              # 目标最大 GC 停顿时间(毫秒)
-XX:G1HeapRegionSize=16m              # Region 大小(1-32M,必须是 2 的幂)
-XX:InitiatingHeapOccupancyPercent=45 # 堆使用率达到多少触发并发 GC

3.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.jar

4. JDK 17 常用参数

JDK 17 是 LTS 版本,默认用 G1 GC

4.1 垃圾收集器选择

bash
# G1(默认)
-XX:+UseG1GC

# ZGC(超低延迟,推荐大堆)
-XX:+UseZGC

# Shenandoah(另一个低延迟收集器)
-XX:+UseShenandoahGC

4.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.jar

ZGC 版本(低延迟场景):

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.jar

5. JDK 21 常用参数

JDK 21 是最新 LTS,默认用 G1 GC,ZGC 已成熟。

5.1 垃圾收集器选择

bash
# G1(默认)
-XX:+UseG1GC

# ZGC(推荐,分代版)
-XX:+UseZGC
-XX:+ZGenerational              # 开启分代 ZGC(JDK 21 新特性)

# Shenandoah
-XX:+UseShenandoahGC

5.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=full

5.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.jar

6. 各版本垃圾收集器对比

收集器JDK 8JDK 17JDK 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=4

8.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.jar

JDK 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 左右的堆,其余留给非堆内存。