JVM进阶调优系列(6)一文详解JVM参数与大厂实战调优模板推荐

本文涉及的产品
云原生网关 MSE Higress,422元/月
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 本文详述了JVM参数的分类及使用方法,包括标准参数、非标准参数和不稳定参数的定义及其应用场景。特别介绍了JVM调优中的关键参数,如堆内存、垃圾回收器和GC日志等配置,并提供了大厂生产环境中常用的调优模板,帮助开发者优化Java应用程序的性能。

读书心得:乐观积极面对挑战,能力与挑战难度相匹配,专注享受当下事宜,无视周边因素,达到忘我状态,时间也会忘记。

    不管是刚入行没多久的JAVA初级级研发还是10年资深架构师,手上都需要珍藏一份JVM参数指南。不仅是为了学习JVM调优,也是时刻方便在实际工作中对业务系统的调优监控做出及时调整。本文全面整理JVM参数清单,并做成表格,以及公开一份大厂生产环境核心常用的调优模板供大家参考应用,希望对有缘刷到的同学有所帮助。

    上一篇文章,末尾我们给了一份jvm参数清单并留了一个问题,说说每个参数的意义?看完本文就能得到完整的答案(坚持授人以鱼,不如授人以渔的原则),尽量不填鸭投喂,希望和大家一起思考提升进步。

一、JVM参数有多少种类型?

    这个分类没有标准答案,大家根据各自理解和应用,会有不同分类。我们采用从参数开头、区域功能类型两大类进行划分,更加贴近实际应用,也方便记忆和学习。

二、按参数开头划分

    首先,大家看一下这份jar包启动参数命令集,先不用想具体含义,看看参数都有哪些特点。

    这里看到里面有的是-X开头,有的是-XX开头,有的是-D开头,有的是-开头。这里我们把-开头的,叫做【标准参数】,-X开头的叫做【非标准参数】,-XX开头的叫做【非稳定参数】。

2.1 标准参数(-开头)

    -开头的标准参数,我们常见的有:-jar,-help,-version,以及-agentpath:[=<选项>]、-javaagent:[=<选项>]都是。

2.1.1 如何查看全部标准参数列表?

    可以通过java -help命令去查看标准参数清单。

2.2 非标准参数(-X开头)

    -X开头的非标准参数,随着JDK的版本变化,参数的变化也很少。这里就有很多熟悉的参数,具体参数含义我们在文末表格里详细说明。这里简略说几个,比如以下三个。

-Xms :设置初始 Java 堆大小;
-Xmx  :设置最大 Java 堆大小;
-Xss   设置 Java 线程堆栈大小;

2.2.1 那如何查看-X开头的非标准参数,如何整理全部JVM参数清单?

    其实也简单,类似非标准参数java -help一样,只要执行java -X 就可以看到全部非标准参数。

2.3 不稳定(UnStable)参数(-XX开头)

     我们常说的JVM调优,应用最多的就是这个-XX开头的参数,它也是最为复杂。而且不同JDK版本、应用不同的垃圾回收器参数都各不相同,非常值得我们深入学习探讨。这些非稳定参数,有的用来选择GC回收器类型、有的用来控制GC日志、有的用来控制GC频率、内存占比划分。比如:


设置年老年用CMS垃圾回收器的-XX:+UseConcMarkSweepGC;
设置年轻代存活对象进入老年代的年龄-XX:MaxTenuringThreshold=10 
设置打印GC日志 -XX:+PrintGC。

    这里发现,不稳定参数的赋值语法还有点复杂,这里细分了几种类型。

2.3.1 不稳定参数赋值语法

1、数字类型参数值

    -XX:=,用=号并赋值数字。

    比如,-XX:SurvivorRatio=8,这个8是JDK的默认值。标识年轻代中Eden区大小/两个Survivor区的大小。也就是在年轻代内存划分,默认比例是Eden:S1:S0 = 8:1:1。

2、布尔类型参数值

    是通过+\-号,来表示启用、禁用。

-XX:+

-XX:-

    比如,刚才这个-XX:+UseConcMarkSweepGC,表示启用CMS垃圾收集器。

3、字符串类型参数值

    通过=并设置字符串值。

-XX:=

    比如:-XX:HeapDumpPath=./log/dump/oom.log,设置内存溢出快照保存地址。

2.3.2 那如何查看全部JVM -XX开头的参数呢?

    之前是java -X查看非标准参数,现在是 java -XX?

(base) MacBook-Pro ~ % java -XX
Unrecognized option: -XX
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

报错了,不能如此类推!这里末尾还需要加+PrintFlagsFinal才可以。

java -XX:+PrintFlagsFinal

三、按区域功能划分

    之前我们的文章系列2《JVM内存区域怎么划分,分别有什么用》有详细说过内存区域划分,里面有堆内存(分年轻代和老年代)、MetaSpace元数据区、虚拟机栈、程序计数器、系统直接内存几个区。老话长谈JVM调优,主要就是对堆内存GC进行调优。所以有必要专门了解整理堆内存相关参数。

3.1 堆内存相关参数

    我们这里把虚拟机栈、堆内存,MetaSpace元数据区相关参数都统一当做堆内存参数。除了刚才说的非标准参数-Xms、-Xmx、-Xmn,还有:

-XX:NewRatio=n,设置年轻代和年老代的比值为n;
-Xss,设置每个线程堆栈大小;
-XX:MaxMetaspaceSize 设置元数据区大小。

3.2 垃圾回收器参数

    与GC垃圾回收器相关的参数,我们划为一类。比如:

-XX:CMSFullGCsBeforeCompaction,CMS回收器完成多少次FGC后进行内存压缩;
-XX:CMSInitiatingOccupancyFraction=92,老年代占比大于92%后开始CMS FGC处理
-XX:+UseParNewGC,使用ParNew回收器来为年轻代做YGC;
-XX:ParallelGCThreads,负责垃圾回收的并发线程数量。

3.3 GC日志、OOM相关参数

    GC日志控制、OOM相关后置处理参数,划为一类。比如:

-XX:GCLogFileSize=n,GC log 滚动大小;
-Xloggc:log/myapp_gc.log,发生gc后相关gc日志保存;
-XX:+HeapDumpOnOutOfMemoryError ,内存溢出时导出整个堆信息,让JVM遇到OOM异常时能输出堆内信息;
-XX:HeapDumpPath=./oomlog/dump/,内存异常堆数据导出地址。

四、大厂生产调优实践参数模板

    在一线头部大厂,通过长期生产实践技术经验积累,基础技术架构组或者相关架构师会整理分享一个jvm最佳实践模板,帮助团队成员根据不同的业务场景快速调整出一份适合自己系统服务的JVM参数。让核心服务首次上线、以及后续业务规模增长,不管监控是否发现性能问题、还是业务爆涨,都能提供长期稳定运行支撑。

    这里分享一份生产实战调优常用(也可以说是必用的核心参数)的一个模板,大家不可盲目照搬直接应用,可以先保存,具体还是要看业务量、业务场景来调整,后续分享实战案例,帮助大家分析选择调优自己的系统服务。

-Xms8888M -Xmx8888M -Xmn6666M -Xss1M -XX:MetaspaceSize=256M 
-XX:MaxMetaspaceSize=256M 
-XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=10
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92
-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=2 
-XX:+CMSParallelInitialMarkEnabled
XX:+CMSScavengeBeforeRemark -XX:+PrintGCApplicationStoppedTime 
-XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps
-Xloggc:gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/mycompany/appname/oom

    这个模板,有些参数是非常必要的,比如:

-XX:+DisableExplicitGC: 关闭System.gc(),程序代码里主动gc是非常糟糕的。
-XX:+CMSParallelInitialMarkEnabled:CMS的初始标记阶段是会Stop the world,导致系统停顿,
加了这个参数可以开启多线程并发进行标记,减少暂停时间。
-XX:CMSScavengeBeforeRemark:CMS的重新标记阶段也是会Stop the world,打开这个参数好处,
就是可以在【重新标记】之前先执行YGC,YGC会回收没有再被年轻代引用的对象。
这样重新标记阶段就可以少扫描一些对象,提高CMS重新标记阶段的性能。

   其他几个,大家看第四部分参数清单去找对应含义和重要性。现附上JVM参数表格。

五、JVM参数详解说明表格

    粗略统计了一下,JDK8 JVM全部参数加起来有将近800个,实际我们常用的以及调优参数大概100多个,这里我们重点列举核心常用的参数。

参数名

参数意义、用法说明

默认值

-Xms

设置初始 Java 堆大小

-Xmx

堆内存可以扩展到最大大小

-Xmn

堆内存里年轻代的大小

默认是8

-Xss

线程堆栈大小,单位是:k或K,表示KB;m或M表示MB;g或G表示GB;

-Xnoclassgc

禁用类的GC垃圾收集

-Xincgc

启用增量垃圾收集

-Xcheck:jni

对 JNI 函数执行其他检查

-Xbatch

禁用后台编译

-Xloggc

指定GC日志路径,-Xloggc:/data/gclog/mygc.log

-Duser.timezone

指定时区

-XX:MaxMetaspaceSize

元数据区最大大小,这个地方放.class类信息

-XX:MetaspaceSize

类元数据区的大小,Metaspace第一次超出该大小时触发垃圾回收。

-XX:ThreadStackSize

线程堆栈大小

默认值1024

-XX:NewRatio

年轻代与年老代的比值,默认是2:1

默认值2

-XX:MaxTenuringThreshold

年轻代对象进入老年代的年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。

默认是15

-XX:LargePageSizeInBytes

内存页大小

-XX:PretenureSizeThreshold

可以直接进入老年代的大对象大小

-XX+BackgroundCompilation

启用后台编译。默认启用。如果禁用,则-XX:-BackgroundCompilation。

XX:+DisableExplicitGC

禁用System.gc()

默认是禁用

-XX:SurvivorRatio

Eden区与Survivor区的大小比值

默认是8,E:S1:S0=8:1:1

-XX: +PrintGCApplicationStoppedTime

打印应用程序由于GC而产生的停顿时间

-XX:ConcGCThreads

并发GC的线程数

-XX:ParallelGCThreads

负责垃圾回收的并发线程数量

-XX:+AggressiveHeap

启用Java堆优化

默认禁用

-XX:CMSInitiatingOccupancyFraction

老年代占比大于该参数比例后开始CMS FGC处理(这个值大于等于0则直接取百分号,小于0则根据公式来计算。往往需要配合-XX:+UseCMSInitiatingOccupancyOnly使用)

默认92

-XX:+CMSScavengeBeforeRemark

打开这个参数,CMS在【重新标记】之前先执行YGC

-XX: +UseCMSInitiatingOccupancyOnly

打开这个参数后,CMS通过CMSInitiatingOccupancyFraction的值进行垃圾回收。

-XX:+UseParNewGC

使用ParNew垃圾收集器

-XX:+UseConcMarkSweepGC

指定使用CMS垃圾回收器

-XX:+CMSClassUnloadingEnabled

CMS垃圾收集器时启用类卸载

默认启用

XX:CMSFullGCsBeforeCompaction

多少次GC后,CMS进行内存碎片整理

-XX:+PrintGCDetails

打印GC详细信息

-XX:+PrintHeapAtGC

打印GC前后详细的堆栈信息

-XX:+PrintReferenceGC

跟踪系统内的软引用,弱引用,虚引用和Finallize队列

-XX:OnOutOfMemoryError=”“

指定这个参数,可以在服务OOM后,执行自定义脚本,比如用来发送邮件告警信息,重启服务。="/opt/local/bin/alert-restart.sh"

-XX:HeapDumpPath =

OOM抛出异常时,将堆数据转储到HeapDumpPath目录

-XX:+PrintGC

简单打印GC日志

-XX:+UseSerialGC

使用串行垃圾收集器

-XX:+UseG1GC

使用G1垃圾回收器

-XX:MaxGCPauseMillis

设置并行收集最大暂停时间

-XX:+ExplicitGCInvokesConcurrent

允许使用System.gc()请求调用并发GC

-XX:+UseGCOverheadLimit

限制OOM异常之前JVM在GC上花费的时间比例

默认启用

.............

推荐阅读:

1、JVM进阶调优系列(3)堆内存的对象什么时候被回收?

2、JVM进阶调优系列(2)字节面试:JVM内存区域怎么划分,分别有什么用?

3、JVM进阶调优系列(1)类加载器原理一文讲透

4、JAVA并发编程系列(13)Future、FutureTask异步小王子

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
打赏
0
1
1
0
106
分享
相关文章
JVM实战—8.如何分析jstat统计来定位GC
本文详细介绍了使用jstat、jmap和jhat等工具分析JVM运行状况的方法,以及如何合理优化JVM性能。内容涵盖新生代与老年代对象增长速率、Young GC和Full GC的触发频率及耗时等关键指标的分析。通过模拟BI系统和计算系统的案例,展示了如何根据实际场景调整JVM参数以减少FGC频率,提升系统性能。最后汇总了常见问题及其解决方案,帮助开发者更好地理解和优化JVM运行状态。
JVM实战—8.如何分析jstat统计来定位GC
JVM实战—10.MAT的使用和JVM优化总结
本文详细探讨了JVM内存管理与性能优化的关键问题。首先分析了线上大促活动引发的老年代内存泄漏及频繁FGC问题,通过MAT工具定位到本地缓存未正确处理的原因,并提出使用Ehcache等框架解决。接着讨论了百万级数据误处理导致的频繁FGC案例,深入剖析String.split()方法在特定JDK版本下的内存消耗问题,并给出多线程并发处理大数据量的优化建议。文章还总结了JVM运行原理、GC机制以及YGC和FGC的触发条件,明确了正常系统GC频率指标。最后提供了JVM性能优化的整体思路,包括新系统开发时的参数预估、压测后的调整策略以及线上系统的监控方法,同时列举了常见的FGC原因及对应解决方案。
120 79
JVM实战—10.MAT的使用和JVM优化总结
JVM实战—11.OOM的原因和模拟以及案例
本文详细探讨了Java系统中内存溢出(OutOfMemory,简称OOM)问题的成因与解决方法。首先分析了线上系统因OOM挂掉的常见场景及处理思路,接着深入讲解了JVM中可能发生OOM的三大区域:Metaspace(类信息存储区)、栈内存(线程执行方法时使用)和堆内存(对象存储区)。针对每个区域,文章通过具体代码示例模拟了内存溢出的情况,如动态生成过多类导致Metaspace溢出、无限递归调用引发栈内存溢出以及高负载下堆内存不足等问题。最后结合实际案例,如大数据处理系统因Kafka故障未正确处理数据缓存而导致OOM,以及无限循环调用或未缓存动态代理类引发的问题,给出了预防和改进措施。
102 64
JVM实战—11.OOM的原因和模拟以及案例
JVM实战—7.如何模拟GC场景并阅读GC日志
本文主要介绍了:如何动手模拟出频繁Young GC的场景、JVM的Young GC日志应该怎么看、编写代码模拟动态年龄判定规则进入老年代、编写代码模拟S区放不下部分进入老年代、JVM的Full GC日志应该怎么看。
JVM实战—7.如何模拟GC场景并阅读GC日志
JVM实战—6.频繁YGC和频繁FGC的后果
本文详细探讨了JVM中的GC机制及其优化策略,涵盖Young GC、Old GC和Full GC的触发条件与影响。首先分析了JVM GC可能导致系统卡顿的问题,特别是大内存机器上的YGC性能瓶颈,并通过G1垃圾回收器解决。接着通过实际案例展示了频繁FGC的成因及优化方法,如调整新生代与老年代内存比例或使用大内存机器。最后总结了不同GC算法的适用场景及对象生命周期特点,为JVM性能调优提供了实用指导。
JVM实战—6.频繁YGC和频繁FGC的后果
JVM实战—13.OOM的生产案例
本文详细探讨了多种线上系统中引发OOM(内存溢出)问题的原因及排查方法。内容涵盖:1)每秒仅上百请求的系统因RPC超时时间设置过长导致QPS激增而OOM;2)Jetty服务器NIO机制因堆外内存管理不当引发内存溢出;3)微服务架构下RPC调用因类定义不一致导致超大byte[]数组占用内存;4)SQL语句缺少WHERE条件查询大量数据引发OOM;5)日志分析系统因堆内存不足与递归操作耗尽内存;6)类加载器过多导致内存使用过高被OS杀死进程;7)数据同步系统频繁OOM的排查与解决;8)总结JVM参数优化、GC问题定位及OOM分析方法。
JVM实战—13.OOM的生产案例
JVM实战—9.线上FGC的几种案例
本文详细探讨了JVM性能优化中的几个关键案例与问题。首先分析了如何优化每秒十万QPS的社交APP,通过增加Survivor区大小和优化内存碎片解决频繁Full GC的问题。接着讨论了垂直电商后台系统FGC的深度优化,定制JVM参数模板以降低GC频率。还探讨了不合理设置JVM参数导致频繁FGC的情况,并提出了解决方案。此外,针对线上系统每天数十次FGC的问题,定位到大对象是主要原因,并通过调整新生代大小等参数优化。同时,分析了电商大促活动中因System.gc()调用导致系统卡死的现象,建议禁用显式GC。
JVM实战—9.线上FGC的几种案例
JVM实战—4.JVM垃圾回收器的原理和调优
本文详细探讨了JVM垃圾回收机制,包括新生代ParNew和老年代CMS垃圾回收器的工作原理与优化方法。内容涵盖ParNew的多线程特性、默认线程数设置及适用场景,CMS的四个阶段(初始标记、并发标记、重新标记、并发清理)及其性能分析,以及如何通过合理分配内存区域、调整参数(如-XX:SurvivorRatio、-XX:MaxTenuringThreshold等)来优化垃圾回收。此外,还结合电商大促案例,分析了系统高峰期的内存使用模型,并总结了YGC和FGC的触发条件与优化策略。最后,针对常见问题进行了汇总解答,强调了基于系统运行模型进行JVM参数调优的重要性。
JVM实战—4.JVM垃圾回收器的原理和调优
JVM实战—12.OOM的定位和解决
本文详细探讨了JVM内存管理中的常见问题及其解决方案,包括如何监控和报警系统的OOM异常、在内存溢出时自动Dump内存快照、解决Metaspace区域内存溢出、栈内存溢出(StackOverflowError)以及堆内存溢出(OutOfMemoryError: Java heap space)。针对每种情况,文章提供了具体的解决思路、示例代码、GC日志分析及内存快照分析方法。通过搭建系统监控体系、调整JVM参数和使用工具如MAT,可以有效定位和解决各类内存问题,优化系统性能并避免崩溃风险。
JVM实战—12.OOM的定位和解决
JVM实战—2.JVM内存设置与对象分配流转
本文详细介绍了JVM内存管理的相关知识,包括:JVM内存划分原理、对象分配与流转、线上系统JVM内存设置、JVM参数优化、问题汇总。
JVM实战—2.JVM内存设置与对象分配流转

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等