当前位置: 首页 > ops >正文

性能优化 - 高级进阶:JVM 常见优化参数

文章目录

    • Pre
    • 1. 引言:Java版本演进与GC演变背景
    • 2. 查看JVM参数默认值的方法
    • 3. 基于ElasticSearch的JVM参数示例分析
      • 3.1 堆空间配置与AlwaysPreTouch
      • 3.2 堆外内存细分
      • 3.3 GC日志配置(Java 8 vs Java 9+)
      • 3.4 OOM时Dump配置
      • 3.5 垃圾回收器配置:CMS示例及迁移
      • 3.6 其他额外参数
    • 4. 常见GC器演进与配置要点
      • 4.1 CMS生命周期与参数
      • 4.2 G1配置要点
      • 4.3 ZGC、Shenandoah简介
      • 4.4 其他GC(Serial、Parallel等)
    • 5. 深入调优:分代比例、SurvivorRatio、TenuringThreshold等
    • 6. 小结与建议

在这里插入图片描述


Pre

性能优化 - 理论篇:常见指标及切入点

性能优化 - 理论篇:性能优化的七类技术手段

性能优化 - 理论篇:CPU、内存、I/O诊断手段

性能优化 - 工具篇:常用的性能测试工具

性能优化 - 工具篇:基准测试 JMH

性能优化 - 案例篇:缓冲区

性能优化 - 案例篇:缓存

性能优化 - 案例篇:数据一致性

性能优化 - 案例篇:池化对象_Commons Pool 2.0通用对象池框架

性能优化 - 案例篇:大对象的优化

性能优化 - 案例篇:使用设计模式优化性能

性能优化 - 案例篇:并行计算

性能优化 - 案例篇:多线程锁的优化

性能优化 - 案例篇:CAS、乐观锁、分布式锁和无锁

性能优化 - 案例篇: 详解 BIO NIO AIO

性能优化 - 案例篇: 19 条常见的 Java 代码优化法则

性能优化 - 案例篇:JVM垃圾回收器

性能优化 - 案例篇:JIT

性能优化 - 案例篇:11种优化接口性能的通用方案


1. 引言:Java版本演进与GC演变背景

Java 8长期以来是企业主力版本,很多公司因稳定性和兼容性选择Java 8并启用CMS垃圾回收器。但从Java 9开始进入半年一版的快速发布模式,Java 8与Java 11成为LTS版本,后续LTS如Java 17、Java 21等陆续推出([en.wikipedia.org][1], [preemptive.com][2])。

随着JVM内部不断演进,CMS在Java 9中被标记为Deprecated,并于Java 14正式移除(见JEP 363)([openjdk.org][3], [oracle.com][4])。新GC器如G1、ZGC、Shenandoah成熟,逐渐成为主流选择。
因此,在不同JVM版本上配置GC参数需先查看默认值,不要盲从他人建议。


2. 查看JVM参数默认值的方法

可以使用以下命令查看参数的默认值和当前生效参数:

java -XX:+PrintFlagsFinal -XX:+UseG1GC 2>&1 | grep UseAdaptiveSizePolicy

上述命令在启动时列出所有Flags的最终值,通过grep过滤目标参数。常见用法还有:

java -XX:+PrintCommandLineFlags -version

输出示例(Java 8默认Parallel GC):

-XX:InitialHeapSize=127905216 -XX:MaxHeapSize=2046483456 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
openjdk version "1.8.0_41"
...

通过这些命令可确认某个参数是否已有默认值,避免重复配置或无效配置。

3. 基于ElasticSearch的JVM参数示例分析

ElasticSearch(ES)作为典型Java应用,其jvm.options提供了常见配置案例,便于学习和参考。

3.1 堆空间配置与AlwaysPreTouch

ES常见配置:

-Xms1g
-Xmx1g
-XX:+AlwaysPreTouch

将-Xms与-Xmx设为相同值可避免动态扩容开销。在堆较大时,-XX:+AlwaysPreTouch会在JVM启动时触碰(touch)所有堆页面,提前向操作系统申请并锁定内存页,增加启动时间,但减少运行时动态分配时的性能损耗,提高稳定性和吞吐([docs.oracle.com][5])。

对于存储型服务(如ES),通常将堆设置为物理内存一半,以留一半给操作系统文件缓存(PageCache),提高I/O效率;对于计算型Web服务,可将堆设置为物理内存2/3,剩余1/3供直接内存、本地内存等使用。

在这里插入图片描述

JVM内存布局:堆与堆外细分、PageCache与JVM堆的关系。 堆外包含元空间、CodeCache、直接内存、本地内存(线程栈、网络缓冲等)及JNI分配等。

3.2 堆外内存细分

  • 元空间(Metaspace):通过-XX:MetaspaceSize-XX:MaxMetaspaceSize可指定初始化与上限;默认无上限可能导致过度使用系统内存,建议根据应用类加载行为适当设置上限。
  • JIT编译后代码存放 CodeCache:JIT编译后代码存储区,通过-XX:ReservedCodeCacheSize设置上限;若CodeCache满,会触发Full GC或影响性能。
  • 直接内存(Direct Memory):ByteBuffer等直接缓冲区申请内存,通过-XX:MaxDirectMemorySize限制,防止内存占用过大。
  • 本地内存(Native Memory):线程栈、JNI malloc、网络连接缓冲等,无法由JVM直接控制,但需关注高并发场景下的本地内存消耗。
  • JNI内存:依赖具体JNI实现,JVM无法控制,但应避免JNI库出现内存泄漏。

3.3 GC日志配置(Java 8 vs Java 9+)

在Java 8中,常用GC日志参数(以ES为例):

-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintTenuringDistribution
-XX:+PrintGCApplicationStoppedTime
-XX:-Xloggc:logs/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=32
-XX:GCLogFileSize=64m

这些参数可打印GC细节、时间戳(系统时间)、年龄分布、STW停顿时间,并配置日志滚动([docs.oracle.com][5])。

Java 9+移除40多个GC日志参数,采用Unified Logging:

-Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m

此方式更统一、灵活,可通过jcmd动态调整([foojay.io][6])。

3.4 OOM时Dump配置

ES常见:

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=data
-XX:ErrorFile=logs/hs_err_pid%p.log

发生OOM时自动生成堆转储文件,用于后续MAT等工具分析问题根因。正常可使用jmap等命令获取堆快照,但生产环境优先配置自动Dump。

3.5 垃圾回收器配置:CMS示例及迁移

ES默认曾使用CMS:

-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
  • UseConcMarkSweepGC表示Young代用ParNew,Old代用CMS。
  • CMSInitiatingOccupancyFraction设定启动并发标记的老年代占用阈值,避免Concurrent Mode Failure;需配合UseCMSInitiatingOccupancyOnly生效。

另外,对于 CMS 垃圾回收器,常用的还有下面的配置参数:

-XX:+ExplicitGCInvokesConcurrent
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSScavengeBeforeRemark
-XX:+ParallelRefProcEnabled
  • -XX:ExplicitGCInvokesConcurrent 当代码里显示的调用了 System.gc(),实际上是想让回收器进行FullGC,如果发生这种情况,则使用这个参数开始并行 FullGC。建议加上。

  • -XX:CMSFullGCsBeforeCompaction 默认为 0,就是每次FullGC都对老年代进行碎片整理压缩,建议保持默认。

  • -XX:CMSScavengeBeforeRemark 开启或关闭在 CMS 重新标记阶段之前的清除(YGC)尝试。可以降低 remark 时间,建议加上。

  • -XX:+ParallelRefProcEnabled 可以用来并行处理 Reference,以加快处理速度,缩短耗时。

CMS在Java 14已移除,不可再用,应转向G1或更现代GC([blog.gceasy.io][7])。

3.6 其他额外参数

  • -Xss1m:设置线程栈大小为1MB,默认即1MB,可根据线程数和调用深度适当调整。
  • -XX:-OmitStackTraceInFastThrow:ES关闭此项以便调试异常;开启可合并重复异常栈以提高性能,但调试困难。
  • -Djava.awt.headless=true:服务器无GUI时需设置Headless模式,避免AWT初始化失败。
  • 其他-D参数如-Dfile.encoding=UTF-8、-Des.networkaddress.cache.ttl=60等,根据应用需求配置网络、编码、临时目录、日志框架等。

4. 常见GC器演进与配置要点

4.1 CMS生命周期与参数

CMS自Java 1.4.1起被引入,目标低延迟,但不压缩老年代容易产生碎片、发生Concurrent Mode Failure导致长STW。Java 9开始Deprecated,Java 14移除(JEP 363)([openjdk.org][3], [oracle.com][4])。建议迁移至G1等。

4.2 G1配置要点

G1自Java 7u14实验性引入,Java 9起默认GC。优点:并发标记、分区回收、自动压缩,提供MaxGCPauseMillis目标设置。常见参数:

  • -XX:+UseG1GC
  • -XX:MaxGCPauseMillis=<期望毫秒>
  • -XX:G1HeapRegionSize=<2的幂,默认通常合适,不建议轻易修改>
  • -XX:InitiatingHeapOccupancyPercent=<启动并发标记阈值,默认45%>
  • -XX:ConcGCThreads=<默认即可>
    G1无需手动设置-Xmn,自动调优分代大小;可通过打印日志分析GC行为,调整Pause目标和Region大小。

4.3 ZGC、Shenandoah简介

  • ZGC:Java 11实验性,Java 15生产就绪,面向超大堆和低停顿(通常<10ms)。使用-XX:+UseZGC启用,需JDK对应版本支持。
  • Shenandoah:类似目标,Java 12实验,Java 15+成熟。
    这些GC适用于大内存、低延迟场景,但需确认应用和平台支持。

4.4 其他GC(Serial、Parallel等)

  • Serial GC(-XX:+UseSerialGC):小堆、单线程场景。
  • Parallel GC(-XX:+UseParallelGC / UseParallelOldGC):追求吞吐,适合批处理。
    选择需根据应用类型(交互型、批处理、超大堆等)决定。

5. 深入调优:分代比例、SurvivorRatio、TenuringThreshold等

  • -Xmn:调整年轻代大小,G1一般无需;在Parallel或CMS可根据业务调整,若对象存活率低可加大年轻代。
  • -XX:SurvivorRatio:Eden和Survivor区比例,默认8,可根据对象晋升行为调整。
  • -XX:MaxTenuringThreshold:对象晋升阈值,CMS下默认6,G1下默认15;可通过-XX:+PrintTenuringDistribution观察年龄分布,若早期代晋升过多,适当降低阈值;若大多数对象在Survivor区很快死亡,适当增大可减少晋升压力。
  • PretenureSizeThreshold:大对象直接分配到老年代,使用少见。
    通过GC日志分析或可视化工具(如GCViewer、GCEasy)观察GC停顿、年轻代/老年代使用情况,再针对性调整。

6. 小结与建议

  • 在不同JVM版本和GC器上,先查看默认参数,不要盲信旧配置;
  • 根据应用类型(存储、计算、低延迟、高吞吐)选择合适堆大小及GC器;
  • 通过-XX:+PrintCommandLineFlags、PrintFlagsFinal、-Xlog或旧日志参数查看生效配置;
  • 合理配置元空间、CodeCache、直接内存等,防止本地内存耗尽;
  • 配置GC日志和OOM自动Dump,便于问题排查;
  • CMS已废弃,迁移至G1或更现代GC;
  • 深入调优需结合GC日志分析工具进行,调整分代比例、停顿目标、并发线程数等;
  • 在生产环境中小幅、渐进式调整,观察效果。
[1]: https://en.wikipedia.org/wiki/Java_version_history?utm_source=chatgpt.com "Java version history"
[2]: https://www.preemptive.com/blog/the-road-to-java-9/?utm_source=chatgpt.com "The Road to Java 9 - PreEmptive Solutions"
[3]: https://openjdk.org/jeps/363?utm_source=chatgpt.com "JEP 363: Remove the Concurrent Mark Sweep (CMS) Garbage ..."
[4]: https://www.oracle.com/java/technologies/javase/14-relnote-issues.html?utm_source=chatgpt.com "JDK 14 Release Notes - java - Oracle"
[5]: https://docs.oracle.com/en/java/java-components/enterprise-performance-pack/epp-user-guide/printing-jvm-information.html?utm_source=chatgpt.com "3 Printing JVM Information - Java - Oracle Help Center"
[6]: https://foojay.io/today/introduction-to-jvm-unified-logging-jep-158-jep-271/?utm_source=chatgpt.com "Introduction to JVM Unified Logging (JEP-158 / JEP-271) - Foojay.io"
[7]: https://blog.gceasy.io/cms-gc-algorithm-removed-from-java-14/?utm_source=chatgpt.com "CMS GC algorithm removed from Java 14?"

在这里插入图片描述

http://www.xdnf.cn/news/14300.html

相关文章:

  • Linux内核网络协议的双重注册机制:inet_add_protocol与inet_register_protosw深度解析
  • Python小酷库系列:Python中的JSON工具库(3)
  • 行为设计模式之State(状态)设计模式
  • java中常见的排序算法设计介绍
  • IDEA21中文乱码解决办法
  • ubuntu 22.04设置时区和24小时制显示——筑梦之路
  • 【详细】CUDA开发学习教程清单
  • 【深度解析】Java高级并发模式与实践:从ThreadLocal到无锁编程,全面避坑指南!
  • Arcgis中,toolbox工具箱中工具莫名报错的解决方法
  • 【速写】policy与reward分词器冲突问题(附XAI阅读推荐)
  • LeetCode--31.下一个排列
  • 行为设计模式之Strategy(策略)
  • 网络编程(HTTP协议)
  • ShenNiusModularity项目源码学习(34:总结)
  • C/C++数据结构之漫谈
  • React-router、React-router-dom、React-router-native之间的区别
  • 基于深度强化学习的智能机器人路径规划系统:技术与实践
  • Flutter 本地存储全面指南:从基础到高级实践
  • CMake实战:qmake转cmake神器 - pro2cmake.py
  • 【图像处理入门】7. 特征描述子:从LBP到HOG的特征提取之道
  • 智慧金融——解读DeepSeek在银行业务场景的应用【附全文阅读】
  • Kotlin实现文件上传进度监听:RequestBody封装详解
  • Vue 性能优化
  • Flink与Kubernetes集成
  • 数据库相关操作
  • [windows工具]OCR提取文字软件1.1使用教程及注意事项
  • Java—— ArrayList 和 LinkedList 详解
  • 【橘子的AI | 每日一课】Day4!机器学习 (ML) 基础
  • /etc/profile.d/conda.sh: No such file or directory : numeric argument required
  • Nginx-2 详解处理 Http 请求