ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

【JVM原理详解】54-常见JVM参数配置指南

【JVM原理详解】54-常见JVM参数配置指南 常见 JVM 参数配置指南引言JVM 参数配置是 Java 应用上线的最后一道关键环节。参数设置不合理轻则性能不佳、GC 频繁重则 OOM 崩溃、服务不可用。然而 JVM 参数多达数百个哪些是必须关注的不同堆大小、不同部署环境物理机/容器下该如何配置本篇将系统梳理生产环境中最常用的 JVM 参数按堆、GC、元空间、直接内存、GC 日志分类讲解并给出 4G/8G/16G 三档堆的推荐参数组合最后覆盖 Docker/K8s 容器环境的特殊注意事项。堆内存参数堆是 JVM 管理对象内存的区域参数配置直接影响 GC 频率和应用吞吐。核心参数参数说明示例-Xms初始堆大小-Xms4g-Xmx最大堆大小-Xmx4g-Xmn新生代大小-Xmn1536m-Xss每个线程的栈大小-Xss512k-Xms 与 -Xmx# 推荐配置初始堆与最大堆设为相同值-Xms4g-Xmx4g为什么建议 Xms Xmx避免堆动态扩展的开销JVM 扩展堆时需要向操作系统申请内存可能引发内存分配延迟减少 GC 抖动堆扩展时可能触发额外的 GC启动即稳定避免运行初期因堆未达最大值而频繁 GC陷阱-Xms设得过大可能导致启动变慢需要一次性分配所有内存且在内存紧张的环境下可能申请失败。对于物理内存充裕的服务器建议 Xms Xmx。-Xmn新生代大小# JDK 8 Parallel GC 场景-Xms4g-Xmx4g-Xmn1536m新生代大小影响 Minor GC 频率。新生代越大Minor GC 越少但老年代相应减小可能增加 Full GC 风险。一般建议新生代占堆的1/3 ~ 1/2。注意-Xmn对G1 GC不推荐使用。G1 通过-XX:G1HeapRegionSize和-XX:MaxGCPauseMillis自行管理分区大小手动设置-Xmn会干扰 G1 的自适应策略。JDK 9 默认 G1应避免使用-Xmn。-Xss线程栈大小# 默认值因平台而异Linux 64位通常 1MB-Xss512k每个线程都会分配独立栈空间。-Xss影响线程数上限和递归深度512K适合大多数 Web 应用能支撑更多线程1M默认递归深度更大但相同内存下线程数减半256K极限场景可能不够用# 线程数与栈大小的关系 可用内存 1G / Xss 1M 约 1000 线程 可用内存 1G / Xss 512K 约 2000 线程GC 参数GC 算法选择JDK 版本默认 GC推荐生产 GCJDK 8Parallel GCG1大堆或 Parallel吞吐优先JDK 9-17G1 GCG1JDK 17G1 GCG1 或 ZGC低延迟场景# 显式指定 G1-XX:UseG1GC# JDK 17 使用 ZGC超低延迟-XX:UseZGCG1 核心参数-XX:UseG1GC-XX:MaxGCPauseMillis200-XX:G1HeapRegionSize8m-XX:InitiatingHeapOccupancyPercent45参数说明默认值调优建议MaxGCPauseMillis期望最大 GC 停顿时间200ms低延迟设 100~200吞吐优先可设 500G1HeapRegionSizeRegion 大小自动1~32M堆 4G 时建议设 8M 或 16MInitiatingHeapOccupancyPercent触发并发标记的堆占用阈值45%老年代增长快可降到 35%G1NewSizePercent新生代最小比例5%一般不调G1MaxNewSizePercent新生代最大比例60%一般不调MaxGCPauseMillis 的理解这是 G1 的软目标G1 会尽量满足但不是硬性保证。设得太小如 50ms会导致 G1 频繁触发 GC 但每次回收量少反而降低吞吐。Parallel GC 参数JDK 8 常用-XX:UseParallelGC-XX:UseParallelOldGC-XX:MaxGCPauseMillis200-XX:GCTimeRatio99-XX:ParallelGCThreads4GCTimeRatio99表示允许 GC 占用 1/(991)1% 的应用时间。ParallelGCThreads默认等于 CPU 核数容器环境需注意是否正确识别。ZGC 参数JDK 15 生产可用-XX:UseZGC-XX:ZAllocationSpikeTolerance2-XX:SoftMaxHeapSize12gZGC 的停顿时间通常1msJDK 16适合超大堆和超低延迟场景。SoftMaxHeapSize是软上限ZGC 会尽量保持堆在此值以下但允许超出直到-Xmx。元空间参数JDK 8 移除永久代后类元数据存放在本地内存的元空间中。-XX:MetaspaceSize256m-XX:MaxMetaspaceSize512m参数说明MetaspaceSize元空间初始容量达到此值触发首次 Full GC用于回收类MaxMetaspaceSize元空间最大容量防止无限制增长MetaspaceSize 的意义这不是初始分配大小而是触发 GC 的阈值。元空间从 0 开始增长达到MetaspaceSize时触发一次 GC 来回收无用的类加载器。建议设为一个合理值如 256M避免元空间较小时频繁触发 Full GC。MaxMetaspaceSize 的作用默认无上限受限于物理内存。建议设置上限防止因类加载泄漏如动态生成类耗尽内存。# 典型配置-XX:MetaspaceSize256m-XX:MaxMetaspaceSize512m直接内存参数直接内存Direct Memory是 NIO 使用的堆外内存不受-Xmx管控。-XX:MaxDirectMemorySize1g为什么需要单独限制Netty、NIO 等大量使用DirectByteBuffer分配堆外内存这些内存不计入堆不受-Xmx限制由 Full GC 时通过 Cleaner 回收不及时不限制可能耗尽物理内存实践建议# 堆 4G 直接内存 1G-Xms4g-Xmx4g-XX:MaxDirectMemorySize1g总内存预算堆(4G) 直接内存(1G) 元空间(512M) 线程栈 JVM自身 ≈ 6G。容器内存限制需留足余量。GC 日志参数GC 日志是排查 GC 问题的关键依据生产环境必须开启。JDK 8 GC 日志-XX:PrintGCDetails-XX:PrintGCDateStamps-XX:PrintGCTimeStamps-XX:PrintGCApplicationStoppedTime-XX:PrintTenuringDistribution-Xloggc:/var/log/gc/gc.log-XX:UseGCLogFileRotation-XX:NumberOfGCLogFiles10-XX:GCLogFileSize50M参数说明PrintGCDetails打印 GC 细节PrintGCDateStamps打印日期时间戳可读PrintGCTimeStamps打印距启动的相对时间PrintGCApplicationStoppedTime打印应用停顿时间STW 持续时间PrintTenuringDistribution打印对象晋升年龄分布UseGCLogFileRotationGC 日志轮转避免单个文件过大JDK 9 统一日志XlogJDK 9 引入了统一日志框架Unified LoggingXlog替代了 JDK 8 的大量分散参数。# 基础配置-Xlog:gc*:file/var/log/gc/gc.log:time,uptime,level,tags:filecount10,filesize50m参数格式-Xlog:tags:output:decorators:file-attributes部分示例说明tagsgc*gc 相关所有标签gc, gcheap, gccpu 等outputfile/var/log/gc/gc.log输出到文件decoratorstime,uptime,level,tags每行附加信息file-attributesfilecount10,filesize50m文件轮转# 完整推荐配置JDK 11/17-Xlog:gc*info,gcheapdebug,gcagetrace:file/var/log/gc/gc.log:time,uptime,level,tags:filecount10,filesize50m# 打印到控制台容器环境常用-Xlog:gc*:stdout:time,uptime,level,tagsGC 日志分析工具GC 日志可导入以下工具分析GCEasygceasy.io在线上传日志生成可视化报告GCViewer开源桌面工具JDK Mission Control结合 JFR 分析生产环境推荐参数组合4G 堆中小型应用# JDK 11/17 G1 GC-Xms4g-Xmx4g-XX:UseG1GC-XX:MaxGCPauseMillis200-XX:G1HeapRegionSize4m-XX:InitiatingHeapOccupancyPercent45-XX:MetaspaceSize256m-XX:MaxMetaspaceSize512m-XX:MaxDirectMemorySize512m-Xss512k-Xlog:gc*:file/var/log/gc/gc.log:time,uptime,level,tags:filecount10,filesize50m-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/data/dump/-XX:ExitOnOutOfMemoryError适用场景QPS 中等1k~5k的 Web 应用、微服务节点。8G 堆中大型应用# JDK 11/17 G1 GC-Xms8g-Xmx8g-XX:UseG1GC-XX:MaxGCPauseMillis200-XX:G1HeapRegionSize8m-XX:InitiatingHeapOccupancyPercent40-XX:ConcGCThreads4-XX:ParallelGCThreads8-XX:MetaspaceSize256m-XX:MaxMetaspaceSize512m-XX:MaxDirectMemorySize1g-Xss512k-Xlog:gc*:file/var/log/gc/gc.log:time,uptime,level,tags:filecount10,filesize50m-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/data/dump/-XX:ExitOnOutOfMemoryError说明8G 堆建议G1HeapRegionSize8mInitiatingHeapOccupancyPercent降到 40% 提前触发并发标记。显式指定ConcGCThreads默认约 1/4 CPU和ParallelGCThreads默认约 5/8 CPU。16G 堆大型应用# JDK 17 G1 或 ZGC# 方案一G1 GC-Xms16g-Xmx16g-XX:UseG1GC-XX:MaxGCPauseMillis200-XX:G1HeapRegionSize16m-XX:InitiatingHeapOccupancyPercent35-XX:ConcGCThreads6-XX:ParallelGCThreads16-XX:G1NewSizePercent20-XX:G1MaxNewSizePercent50-XX:MetaspaceSize512m-XX:MaxMetaspaceSize1g-XX:MaxDirectMemorySize2g-Xss512k-Xlog:gc*:file/var/log/gc/gc.log:time,uptime,level,tags:filecount20,filesize100m-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/data/dump/-XX:ExitOnOutOfMemoryError# 方案二ZGCJDK 17超低延迟-Xms16g-Xmx16g-XX:UseZGC-XX:SoftMaxHeapSize12g-XX:ZAllocationSpikeTolerance2-XX:MetaspaceSize512m-XX:MaxMetaspaceSize1g-XX:MaxDirectMemorySize2g-Xss512k-Xlog:gc*:file/var/log/gc/gc.log:time,uptime,level,tags:filecount20,filesize100m-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/data/dump/说明16G 堆建议 Region 设为 16MIHOP降到 35%。如果延迟要求极高P99 10ms考虑 ZGC——它的停顿时间不随堆增大而增加。关键附加参数以上配置都包含以下关键参数# OOM 时自动 dump-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/data/dump/# OOM 后退出避免进程僵死-XX:ExitOnOutOfMemoryErrorExitOnOutOfMemoryError让 JVM 在 OOM 时直接退出配合容器编排K8s自动重启比让进程在异常状态继续运行更安全。容器环境注意事项Docker/K8s 下的内存识别早期 JDK8u131 之前无法正确识别容器的 CPU 和内存限制会按宿主机规格设置默认值导致 OOM 或 GC 线程过多。-XX:UseContainerSupportJDK 8u191 和 JDK 10 引入了容器感知支持# JDK 8u191 / JDK 10 默认开启-XX:UseContainerSupport开启后JVM 会读取 cgroup 信息内存按容器限制计算默认堆大小容器内存的 1/4CPU按容器核数计算 GC 线程数容器环境推荐配置# Dockerfile 中的 JVM 参数示例# 容器内存限制 4GENVJAVA_OPTS-XX:UseContainerSupport \ -XX:MaxRAMPercentage75.0 \ -XX:InitialRAMPercentage75.0 \ -XX:MinRAMPercentage75.0 \ -XX:UseG1GC \ -XX:MaxGCPauseMillis200 \ -Xlog:gc*:stdout:time,uptime,level,tags \ -XX:HeapDumpOnOutOfMemoryError \ -XX:HeapDumpPath/data/dump/ENTRYPOINT[sh,-c,java$JAVA_OPTS-jar app.jar]RAMPercentage 参数-XX:MaxRAMPercentage75.0-XX:InitialRAMPercentage75.0-XX:MinRAMPercentage75.0相比直接写-XmxRAMPercentage按容器内存的百分比计算堆大小更适合弹性伸缩场景。不同规格的容器复用同一镜像无需修改参数。参数作用MaxRAMPercentage容器内存 0G 时生效InitialRAMPercentage初始堆占比MinRAMPercentage容器内存较小时生效 约 200M为什么设 75% 而不是 100%剩余 25% 需要留给元空间Metaspace直接内存Direct Memory线程栈每线程约 512K~1MJVM 内部数据结构CodeCache、CardTable 等操作系统和其他进程容器环境的常见陷阱内存超限被 OOM Kill容器内存限制 4G但-Xmx4g 元空间 直接内存 栈 4G触发 Linux OOM Killer。对策用MaxRAMPercentage75留足余量或显式设置较小的直接内存上限。CPU 限制导致 GC 线程过多容器限制 2 核但 JVM 按宿主机 32 核设置ParallelGCThreads20。对策JDK 8u191 开启UseContainerSupport后会自动识别或显式指定-XX:ParallelGCThreads2。GC 日志文件无法写入容器内文件系统只读。对策GC 日志输出到 stdout-Xlog:gc*:stdout由容器日志系统收集。HeapDump 文件丢失容器退出后文件消失。对策挂载持久化卷到/data/dump/或上传到对象存储。# K8s 部署示例apiVersion:v1kind:Podspec:containers:-name:appresources:limits:memory:4Gicpu:2requests:memory:4Gicpu:2volumeMounts:-name:dump-volmountPath:/data/dumpvolumes:-name:dump-volpersistentVolumeClaim:claimName:heap-dump-pvc时区问题GC 日志时间戳可能使用 UTC。对策设置TZAsia/Shanghai环境变量或在-Xlog的 decorators 中使用uptime相对时间避免时区混淆。实践要点参数配置原则从默认值开始JDK 的默认参数经过大量优化G1 的默认配置对大多数应用已经足够。不要盲目调参先压测验证默认值是否满足需求。一次只改一个参数调优是科学实验同时改多个参数无法判断哪个起了作用。每次修改后压测对比。GC 日志必开无论是否调优GC 日志是事后分析的唯一依据。磁盘空间通过轮转控制开销极低。监控先行调优前先建立监控基线通过 Prometheus Grafana 或 JFR了解当前 GC 频率、停顿时间、内存使用模式才能判断调优是否有效。常见误区-Xmx越大越好堆过大导致 Full GC或 G1 的 Mixed GC停顿时间拉长。单次停顿可能从 200ms 涨到数秒反而影响延迟。MaxGCPauseMillis 设得越小越好设得太小会导致 G1 频繁回收但每次量少吞吐下降。200ms 是个合理起点。关闭 GC 日志省性能GC 日志开销可忽略 0.1%但关闭后出问题无法分析得不偿失。System.gc()有用手动触发 GC 几乎总是有害的。建议加-XX:DisableExplicitGC禁用防止第三方库调用System.gc()干扰 GC 策略。小结堆参数-Xms-Xmx避免动态扩展-Xmn仅 Parallel GC 使用G1 不推荐-Xss默认 512K 适合大多数场景。GC 参数JDK 9 默认 G1通过MaxGCPauseMillis和IHOP控制行为JDK 17 低延迟场景考虑 ZGC。元空间设置MaxMetaspaceSize防止类加载泄漏耗尽内存MetaspaceSize控制首次 GC 阈值。直接内存必须通过MaxDirectMemorySize限制否则 NIO/Netty 可能耗尽物理内存。GC 日志生产必开。JDK 8 用-XX:PrintGCDetails系列JDK 9 用-Xlog:gc*统一日志。容器环境开启UseContainerSupport用MaxRAMPercentage替代硬编码堆大小GC 日志输出到 stdoutHeapDump 挂载持久化卷。
返回列表