读书心得:乐观积极面对挑战,能力与挑战难度相匹配,专注享受当下事宜,无视周边因素,达到忘我状态,时间也会忘记。
不管是刚入行没多久的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上花费的时间比例 |
默认启用 |
............. |
推荐阅读: