JVM 常用参数速查手册
所有参数基于 HotSpot JVM。参数后标注版本状态[JDK8]仅 JDK 8 可用[JDK17]需要 JDK 17 及以上[已移除]表示在后续版本中被删除。LTS 版本关键差异速查Java 的 LTS长期支持版本是8、11、17、21、25。跨版本升级时JVM 参数有实质性变化的集中在以下几个点参数行为差异一览差异点JDK 8JDK 11JDK 17JDK 21JDK 25默认 GCParallel GCG1G1G1G1CMS 收集器✅ 可用⚠️ 已废弃❌ 已移除❌❌ZGC❌实验性✅ 生产可用✅分代 ZGC✅ 分代为唯一模式非分代已移除Shenandoah❌❌✅ 生产可用✅✅GC 日志格式-Xloggc旧格式-Xlog统一格式-Xlog-Xlog-Xlog偏向锁默认开启默认开启默认关闭已移除已移除强封装 JDK 内部不封装不封装强封装--add-opens必须同 17同 17Metaspace刚替换永久代稳定稳定稳定稳定Flight Recorder仅 Oracle JDK✅ 免费开放✅✅✅字符串去重默认关闭默认关闭默认关闭默认开启默认开启虚拟线程❌❌❌✅正式发布✅NMTNative Memory Tracking需显式开启需显式开启需显式开启支持detail级别同 21已废弃 / 已移除参数对照升级 JDK 时启动脚本里的这些参数必须改掉否则 JVM 会报错或静默忽略。旧参数状态替代方案-XX:PermSizeNJDK ≤ 7 可用JDK 8 起忽略有警告-XX:MetaspaceSizeN-XX:MaxPermSizeNJDK ≤ 7 可用JDK 8 起忽略有警告-XX:MaxMetaspaceSizeN-XX:UseConcMarkSweepGCJDK 9 废弃JDK 14 移除-XX:UseG1GC或-XX:UseZGC-XX:UseParNewGCJDK 9 废弃JDK 14 移除由 G1/ZGC 自动处理-XX:CMSIncrementalModeJDK 9 废弃JDK 14 移除无直接替代-XX:UseBiasedLockingJDK 15 废弃JDK 18 默认关闭无需替代JVM 自动选择锁策略-XX:BiasedLockingStartupDelayJDK 15 废弃JDK 18 默认关闭无需替代-XX:PrintGCDetailsJDK 9 废弃-Xlog:gc*-XX:PrintGCDateStampsJDK 9 废弃-Xlog:gc*:...time-Xloggc:fileJDK 9 废弃-Xlog:gc*:filepath-XX:PrintTenuringDistributionJDK 9 废弃-Xlog:gcagetrace-XX:PrintReferenceGCJDK 9 废弃-Xlog:gcrefdebug-XX:PrintAdaptiveSizePolicyJDK 9 废弃-Xlog:gcergo*trace-XX:PrintHeapAtGCJDK 9 废弃-Xlog:gcheapdebug-XX:MaxGCMinorPauseMillisJDK 23 废弃-XX:MaxGCPauseMillis从 JDK 8 升级到 JDK 17 的参数改造清单这是最常见的升级路径需要改的东西最多# ═══ 必须改 ═══ # 1. GC 收集器CMS 已移除换 G1 或 ZGC - -XX:UseConcMarkSweepGC -XX:UseParNewGC -XX:UseG1GC # 2. GC 日志旧格式全部换掉 - -XX:PrintGCDetails - -XX:PrintGCDateStamps - -Xloggc:/var/log/app/gc.log -Xlog:gc*,gcagetrace:file/var/log/app/gc.log:time,uptime,level,tags:filecount5,filesize10m # 3. 永久代参数删掉 - -XX:PermSize256m - -XX:MaxPermSize512m -XX:MetaspaceSize256m -XX:MaxMetaspaceSize512m # 4. 偏向锁JDK 17 已默认关闭显式开启反而有警告 - -XX:UseBiasedLocking # ↑ 直接删除此行不需要替代 # 5. 强封装如果用反射访问 JDK 内部类必须加 --add-opens --add-opens java.base/java.langALL-UNNAMED --add-opens java.base/java.utilALL-UNNAMED # ═══ 建议改 ═══ # 6. Flight Recorder 现在免费了可以加上 -XX:StartFlightRecordingduration60s,filename/tmp/jfr.jfr # 7. G1 成为默认 GC可以不显式指定但建议还是写上明确意图从 JDK 17 升级到 JDK 21 的参数改造相对平滑主要变化# ═══ 建议改 ═══ # 1. 分代 ZGC 大幅提升低延迟场景强烈推荐 - -XX:UseZGC -XX:UseZGC -XX:ZGenerational # 2. 虚拟线程正式发布不需要 JVM 参数但需要 JDK 21 # 代码层面使用 Executors.newVirtualThreadPerTaskExecutor() # 3. 字符串去重默认开启减少内存一般不用管 # ═══ 注意 ═══ # 4. 偏向锁参数已被移除如果还在用会报错 - -XX:UseBiasedLocking # ↑ 必须删除JDK 18 默认关闭JDK 19 参数已移除 # 5. G1 默认 Region 大小算法优化通常不需要手动设了 # 如果之前手动设了 G1HeapRegionSize可以试试去掉让 JVM 自己选容器环境专属参数Docker / K8s这是最容易踩坑的地方。JVM 在容器里看到的可能不是容器的资源限制而是宿主机的。容器感知Container Awareness参数说明默认值建议-XX:UseContainerSupport启用容器感知JVM 读取 cgroup 限制JDK 10默认开启JDK 8u191 才有此参数8u191 之前必须手动升级 JDK-XX:-UseContainerSupport禁用容器感知—几乎不要关除非你确定容器限制不合理-XX:MaxRAMPercentageN堆占容器可用内存的百分比25%JDK 8~21/50%JDK 22专用容器设75共享容器设50~60-XX:InitialRAMPercentageN初始堆占容器可用内存的百分比1.5625%通常不用设配合-Xms-XX:MinRAMPercentageN小内存时的最小堆百分比50%通常不用改为什么这很重要 — 不设置的后果场景Docker 容器限制 4GB 内存宿主机 64GB JDK 8u190无容器感知 JVM 看到 64GB → -Xmx 默认 16GB → 容器被 OOM Killed JDK 8u191有容器感知 JVM 看到 4GB → -Xmx 默认 1GB25%→ 正常运行但堆太小 正确配置 -XX:UseContainerSupport -XX:MaxRAMPercentage75 → JVM 看到 4GB → -Xmx 约 3GB → 合理 ✅容器里的 CPU 核数场景容器限制 2 核宿主机 32 核 JDK 默认行为 Runtime.getRuntime().availableProcessors() → 32宿主机核数 ParallelGCThreads → 32 → 创建 32 个 GC 线程 → 浪费内存 上下文切换 解决方案 1. JDK 10自动读取 cgroup CPU 限制 ✅ 2. JDK 8手动指定 -XX:ParallelGCThreads2 -XX:ConcGCThreads1 3. 或者设置 -XX:ActiveProcessorCount2JDK 8u191参数说明建议-XX:ActiveProcessorCountN覆盖 JVM 检测到的 CPU 核数设为容器实际的 CPU limitJDK 10 通常自动正确容器环境推荐配置# Docker 容器通用模板JDK 17java\-XX:UseContainerSupport\# 启用容器感知-XX:MaxRAMPercentage75\# 堆占容器内存的 75%-XX:InitialRAMPercentage75\# 初始堆也一样避免扩容-XX:UseG1GC\-XX:MaxGCPauseMillis100\-XX:HeapDumpOnOutOfMemoryError\-XX:HeapDumpPath/tmp/heapdump.hprof\-Xlog:gc*:file/var/log/app/gc.log:time,uptime:filecount3,filesize10m\-jarmyapp.jar注意MaxRAMPercentage75意味着堆占 75%剩下 25% 给堆外内存。容器内存越紧张这个值越要精确计算。一、堆内存参数参数说明默认值建议-Xms初始堆大小物理内存的 1/64设为与-Xmx相同避免运行时动态扩容的开销和 STW-Xmx最大堆大小物理内存的 1/4根据服务器可用内存计算见 tuning.md-Xmn新生代大小堆的约 1/3通常为堆的 1/3~1/2设太大会挤压老年代-Xss每个线程的栈大小1MB (64位)256k~512k 通常够用线程多时减小可节省内存要点-Xms和-Xmx设成一样是最重要的一条规则 — 消除扩容带来的停顿-Xmn和-XX:NewRatio二选一不要同时设二、分代与晋升参数参数说明默认值建议-XX:NewRatio老年代:新生代的比例2即老年代占 2/3一般不用改对象创建密集可调为 1-XX:SurvivorRatioEden:每个 Survivor 的比例8即 8:1:1Survivor 放不小可调小如 6让 Survivor 更大-XX:MaxTenuringThreshold对象在 Survivor 中经历 GC 的次数上限15默认 15 通常够用频繁晋升到老年代可适当调大-XX:PretenureSizeThreshold超过此大小的对象直接进老年代0不启用仅 Serial/ParNew 生效G1 用-XX:G1HeapRegionSize间接控制-XX:DisableExplicitGC禁用System.gc()不禁用建议加上防止代码或第三方库乱调 GC-XX:AlwaysPreTouch启动时预分配并触碰所有堆内存页关闭生产环境建议开启避免运行时分配内存页的延迟Survivor 放不下的判断# 观察 GC 日志中是否有 Desired survivor size XXX bytes, new threshold N # 如果 threshold 被自动调低了如降到 3说明 Survivor 太小 # 解决减小 SurvivorRatio如从 8 改为 6增大 Survivor 空间三、元空间参数参数说明默认值建议-XX:MetaspaceSize元空间初始大小约 20MB设为 256m避免启动时频繁触发 GC 扩容-XX:MaxMetaspaceSize元空间最大大小无上限建议设一个上限如 512m防止无限增长什么时候该关注Spring Boot 大量 AOP 代理 → 动态生成很多类热部署 / 频繁重新加载 → 类卸载不及时OOM: Metaspace → 先排查是否有类加载泄漏再调大上限JDK ≤ 7 用户注意永久代参数-XX:PermSize/-XX:MaxPermSize从 JDK 8 起已被忽略启动时会打印警告。升级到 JDK 8 后应替换为上方表格中的-XX:MetaspaceSize/-XX:MaxMetaspaceSize。完整的新旧参数对照见 已废弃 / 已移除参数对照。四、GC 收集器选择参数参数收集器适用场景JDK 要求-XX:UseSerialGCSerial Serial Old单核 / 嵌入式 / 内存 100MB所有版本-XX:UseParallelGCParallel Scavenge Parallel Old高吞吐、批处理、不在乎延迟所有版本JDK 8 默认-XX:UseParNewGCParNew配合 CMS[JDK8] CMS 的新生代搭档JDK 8-XX:UseConcMarkSweepGCCMS[JDK8] 低延迟JDK 8JDK 14 移除-XX:UseG1GCG1通用首选堆 ≤ 16GJDK 7JDK 9 默认-XX:UseZGCZGC大堆 极低延迟JDK 15 正式发布JDK 17 生产推荐-XX:UseShenandoahGCShenandoah低延迟类似 ZGCJDK 15OpenJDK选择决策JDK 版本 ├── JDK ≤ 8 → 延迟敏感 │ ├── 是 → -XX:UseConcMarkSweepGCCMS │ └── 否 → -XX:UseParallelGC默认 ├── JDK 9~14 → -XX:UseG1GC默认通用最优 └── JDK 15 → 延迟要求 ├── 极低 1ms→ -XX:UseZGC ├── 中等 200ms→ -XX:UseG1GC默认 └── 不在乎 → -XX:UseParallelGC五、GC 行为调优参数通用参数参数说明建议-XX:ParallelGCThreadsNGC 并行线程数STW 阶段默认 CPU 核数≤8 时8 核以上8 (N-8)*5/8-XX:ConcGCThreadsNGC 并发线程数不停顿阶段默认 ParallelGCThreads 的 1/4-XX:GCTimeRatioN吞吐量目标应用时间 / GC 时间 ≥ N默认 99即 GC 时间 ≤ 1%G1 专用参数参数说明默认值建议-XX:MaxGCPauseMillisN目标最大 GC 停顿时间200ms根据业务 SLA 设定如 Web 服务 100~200ms-XX:G1HeapRegionSizeNRegion 大小自动1~32MB堆大时可设为 8m 或 16m-XX:InitiatingHeapOccupancyPercentN堆占用率达到多少时触发并发标记45%默认 45%频繁 Full GC 可调低如 35-XX:G1ReservePercentN保留多少空间防止 to-space exhausted10%默认 10%大对象多可调高-XX:G1MixedGCCountTargetNMixed GC 的轮次目标8调大可以分摊每轮的回收量-XX:G1HeapWastePercentN老年代可回收垃圾低于此比例时停止 Mixed GC5%默认 5%设低可以继续回收更多垃圾Parallel GC 专用参数参数说明建议-XX:MaxGCPauseMillisN目标最大停顿时间Parallel GC 会自适应调整-XX:MaxGCMinorPauseMillisN目标 Minor GC 最大停顿同上-XX:GCTimeRatioN吞吐量比例目标默认 99批处理可调到 19GC ≤ 5%-XX:UseAdaptiveSizePolicy自适应调节新生代大小默认开启建议保持ZGC 专用参数参数说明默认值建议-XX:MaxGCPauseMillisN目标停顿时间1msZGC 默认就是亚毫秒通常不用调-XX:SoftMaxHeapSizeN软性堆上限ZGC 会尽量不超无设成接近-Xmx帮助 ZGC 更积极地回收-XX:ZCollectionIntervalN固定 GC 间隔秒0不固定0需要定期回收可设如 120-XX:ZGenerational启用分代 ZGC吞吐延迟双优关闭JDK 21/默认开启JDK 23JDK 21 低延迟场景强烈推荐JEP 439生产特性六、GC 日志参数JDK 9 统一日志格式推荐# 基础配置GC 日志输出到文件滚动保留 5 个文件每个 10MB-Xlog:gc*:file/var/log/app/gc.log:time,uptime,level,tags:filecount5,filesize10m# 详细配置包含 GC、堆、元空间信息-Xlog:gc*,gcheapdebug:file/var/log/app/gc.log:time,uptime,level,tags:filecount5,filesize20m# 打印安全点信息排查 STW 延迟-Xlog:gcsafepointinfo:file/var/log/app/gc.logJDK 8 格式旧# 基础配置-XX:PrintGCDetails-XX:PrintGCDateStamps-Xloggc:/var/log/app/gc.log# 详细配置-XX:PrintGCDetails-XX:PrintGCDateStamps-XX:PrintTenuringDistribution# 打印对象晋升年龄分布-XX:PrintHeapAtGC# GC 前后堆信息-XX:PrintReferenceGC# 引用处理耗时-Xloggc:/var/log/app/gc.log# 大堆时打印堆区域变化G1-XX:PrintAdaptiveSizePolicy日志中看什么# JDK 9 格式示例 [2024-01-15T10:30:05.1230800][12.345s][info][gc] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 209M-45M(2048M) 8.234ms ↑ ↑ ↑ ↑ ↑ 第几次GC 类型 触发原因 前→后 耗时 关键指标 - 频率Young GC 几分钟一次正常Full GC 几小时一次以上就有问题 - 耗时Young GC 50ms 正常Full GC 200ms 可接受 - 回收后使用率GC 后仍 80% → 堆不够或有泄漏七、引用类型与 GC 行为Java 有四种引用类型GC 对它们的回收策略完全不同。理解这个对写缓存、避免 ThreadLocal 泄漏至关重要。引用类型创建方式GC 行为典型用途强引用Object o new Object()只要强引用存在永远不回收普通变量绝大多数场景软引用SoftReferenceObject sr new SoftReference(obj)内存不足时才回收缓存内存紧张时自动清理弱引用WeakReferenceObject wr new WeakReference(obj)下次 GC 就回收不管内存够不够ThreadLocal、WeakHashMap虚引用PhantomReferenceObject pr new PhantomReference(obj, queue)随时可回收无法通过引用获取对象跟踪对象被回收的时机资源清理GC 回收优先级强引用 → 永不回收OOM 也不回收 ↓ 失去强引用后 软引用 → 内存不足时回收GC 会尽量保留 ↓ 失去软引用后 弱引用 → 下次 GC 立刻回收 ↓ 失去弱引用后 虚引用 → 入队通知对象已死实际影响// 1. 软引用做缓存 — 内存紧张时自动清理MapString,SoftReferencebyte[]cachenewHashMap();cache.put(key,newSoftReference(newbyte[1024*1024]));// 2. ThreadLocal 用弱引用 — 但 key 弱引用不意味着 value 也弱// ThreadLocalMap 的 key 是弱引用value 是强引用// → 线程不销毁时 value 永远不会被回收 → 内存泄漏ThreadLocalSessionsessionThreadLocal.withInitial(Session::new);// 必须在使用完后显式 remove()session.remove();// 3. WeakHashMap — key 被回收时整个 entry 自动移除MapKey,ValuemapnewWeakHashMap();GC 调优相关大量软引用对象 → Minor GC 时需要额外判断内存是否充足可能拖慢 GC-XX:SoftRefLRUPolicyMSPerMBN控制软引用的存活时间默认 1000ms/MB 空闲堆调小可以更积极地回收软引用八、JIT 编译参数参数说明建议-XX:TieredCompilation启用分层编译C1 C2JDK 8 默认开启不要关-XX:CompileThresholdN方法编译阈值调用多少次触发 JIT默认 10000分层编译下自动调节一般不改-XX:ReservedCodeCacheSizeNJIT 编译后的机器码缓存大小默认 240MB大型应用可调到 512m-XX:PrintCompilation打印 JIT 编译事件排查编译问题时临时开启-XX:-UseCompilation禁用 JIT纯解释执行永远不要在生产环境用仅供调试九、直接内存参数参数说明默认值建议-XX:MaxDirectMemorySizeN直接内存最大大小等于-Xmx不用 NIO 可设小如 256mNIO 密集按需调大什么时候关注Netty / NIO 应用 → 直接内存用量大OOM: Direct buffer memory → 检查是否有 buffer 未释放十、诊断与调试参数OOM 时自动保存现场# 发生 OOM 时自动 dump 堆必加-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/var/log/app/heapdump.hprof# OOM 时直接退出进程配合 K8s 自动重启容器环境必加-XX:ExitOnOutOfMemoryError# OOM 时执行自定义脚本如发告警-XX:OnOutOfMemoryError/opt/scripts/oom-alert.sh %p参数说明建议-XX:HeapDumpOnOutOfMemoryErrorOOM 时自动导出堆转储生产环境必加-XX:HeapDumpPathN堆转储文件路径指向有足够空间的目录-XX:ExitOnOutOfMemoryErrorOOM 时直接退出 JVM容器环境必加配合 K8s 自动重启-XX:OnOutOfMemoryErrorcmdOOM 时执行自定义命令用于发告警或执行清理脚本JFRJava Flight Recorder# JDK 11 免费使用JDK 8 需 Oracle JDK-XX:StartFlightRecordingduration60s,filename/tmp/recording.jfr-XX:FlightRecorderOptionsstackdepth128常用诊断开关参数说明场景-XX:PrintFlagsFinal启动时打印所有 JVM 参数的最终值确认参数是否生效-XX:PrintVMOptions打印启动时的 JVM 选项排查启动问题-verbose:gc每次 GC 打印一行摘要快速观察 GC 行为-XX:UnlockDiagnosticVMOptions解锁诊断参数使用高级诊断参数时需要先加这个-XX:PrintSafepointStatistics打印安全点统计排查 STW 延迟-XX:NativeMemoryTrackingsummary跟踪 JVM 本地内存使用jcmd pid VM.native_memory summary查看十一、常用 JDK 诊断命令速查命令用途示例jps -l列出 Java 进程找到目标进程 PIDjstat -gcutil pid 1000每秒打印 GC 使用率实时观察 GC 状态jstat -gc pid 1000 10每秒打印 GC 详情共 10 次详细分析jmap -heap pid查看堆配置和使用情况快速检查堆状态jmap -dump:formatb,fileheap.hprof pid导出堆转储MAT 分析内存泄漏jmap -histo pid对象数量和大小的直方图快速找大对象jstack pid线程堆栈快照排查死锁、CPU 高jstack -l pid线程堆栈 锁信息排查锁竞争jinfo -flags pid查看 JVM 启动参数确认线上参数jcmd pid VM.flags查看 JVM 参数同 jinfojcmd pid GC.heap_dump /tmp/dump.hprof堆转储推荐替代 jmap对生产影响更小jcmd pid VM.native_memory summary本地内存概况需开启 NMTArthas生产环境推荐# 安装curl-Ohttps://arthas.aliyun.com/arthas-boot.jarjava-jararthas-boot.jar# 常用命令dashboard# 实时仪表盘线程、内存、GCthread-n3# CPU 最高的 3 个线程watchcom.example.Service getUser{params, returnObj, throwExp}-n5# 观察方法调用trace com.example.Service getUser#cost 100# 方法耗时追踪sc-dcom.example.Service# 查看类加载信息jad com.example.Service# 反编译确认线上代码版本