在学习完整个JVM内容后,其实目标不仅是学习了解整个JVM的基础知识,而是为了进行JVM性能调优做准备,所以以下的内容就是来说说JVM性能调优的知识。
性能调优包含多个层次,比如:架构调优、代码调优、JVM调优、数据库调优、操作系统调优等等。
架构调优和代码调优是JVM调优的基础,其中架构调优是对系统影响最大的。
性能调优基本上按照以下步骤进行:
遇到以下情况,就需要考虑进行JVM调优了:
JVM调优是一个手段,但并不一定所有问题都可以通过JVM进行调优解决;因此,在进行JVM调优时,我们要遵循一些原则:
通过以上原则,我们发现,其实最有效的优化手段是架构和代码层面的优化,而JVM优化则是最后不得已的手段,也可以说是对服务器配置的最后一次“压榨”。
调优的最终目的都是为了令应用程序使用最小的硬件消耗来承载更大的吞吐。JVM调优主要是针对垃圾收集器的收集性能优化,令运行在虚拟机上的应用能够使用更少的内存以及延迟获取更大的吞吐量,总结以下:
其中任何一个属性性能的提高,几乎都是以牺牲其他属性性能的损为代价的,不可兼得。具体根据在业务中的重要性确定。
下面展示了一些JVM调优的量化目标参考实例:
注意:不同应用的JVM调优量化目标是不一样的。
一般情况下,JVM调优可通过以下步骤进行:
以上操作步骤中,某些步骤是需要多次不断迭代完成的。一般是从满足程序的内存使用需求开始的,之后是时间延迟的要求,最后才是吞吐量的要求,要基于这个步骤来不断优化,每一个步骤都是进行下一步的基础,不可逆行之。
JVM调优最重要的工具就是JVM参数。先来了解一下JVM参数相关内容。
-XX 参数被称为不稳定参数,**此类参数的设置很容易引起JVM性能上的差异,使 JVM 存在极大的不稳定性。**如果此类参数设置合理将大大提高JVM的性能及稳定性。
不稳定参数语法规则包含以下内容:
例如以下参数实例:
-Xmx4g
–Xms4g
–Xmn1200m
–Xss512k
-XX:NewRatio=4
-XX:SurvivorRatio=8
-XX:PermSize=100m
-XX:MaxPermSize=256m
-XX:MaxTenuringThreshold=15
上面为Java7及以前版本的示例,**在Java8中永久代的参数-XX:PermSize和-XX:MaxPermSize已经失效。**这在前面章节中已经讲到。
参数解析:
新生代、老生代、永久代的参数,如果不进行指定,虚拟机会自动选择合适的值,同时也会基于系统的开销自动调整。
可调优参数:
-Xms:初始化堆内存大小,默认为物理内存的1/64(小于1GB)。
-Xmx:**堆内存最大值。**默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。
-Xmn:新生代大小,包括Eden区与2个Survivor区。
-XX:SurvivorRatio=1:Eden区与一个Survivor区比值为1:1。
-XX:MaxDirectMemorySize=1G:**直接内存。**报java.lang.OutOfMemoryError: Direct buffer memory异常可以上调这个值。
-XX:+DisableExplicitGC:禁止运行期显式地调用System.gc()来触发fulll GC。
注意: Java RMI的定时GC触发机制可通过配置-Dsun.rmi.dgc.server.gcInterval=86400来控制触发的时间。
-XX:CMSInitiatingOccupancyFraction=60:老年代内存回收阈值,默认值为68。
-XX:ConcGCThreads=4:CMS垃圾回收器并行线程线,推荐值为CPU核心数。
-XX:ParallelGCThreads=8:新生代并行收集器的线程数。
-XX:MaxTenuringThreshold=10:**设置垃圾最大年龄。**如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。
-XX:CMSFullGCsBeforeCompaction=4:指定进行多少次fullGC之后,进行tenured区 内存空间压缩。
-XX:CMSMaxAbortablePrecleanTime=500:当abortable-preclean预清理阶段执行达到这个时间时就会结束。
注意:在设置的时候,如果关注性能开销的话,应尽量把永久代的初始值与最大值设置为同一值,因为永久代的大小调整需要进行FullGC才能实现。
当JVM运行稳定之后,触发了FullGC我们一般会拿到如下信息:
以上gc日志中,在发生fullGC之时,整个应用的堆占用以及GC时间。为了更加精确需多次收集,计算平均值。或者是采用耗时最长的一次FullGC来进行估算。上图中,老年代空间占用在93168kb(约93MB),以此定为老年代空间的活跃数据。则其他堆空间的分配,基于以下规则来进行。
基于以上规则,则对参数定义如下:
-Xms373m -Xmx373m //4*93=372
-Xmn140m //1.5*93=139.5
-XX:PermSize=5m -XX:MaxPermSize=5m //1.5*3=4.5
对延迟性优化,首先需要了解延迟性需求及可调优的指标有哪些。
其中,**平均停滞时间和最大停顿时间,对用户体验最为重要。**对于上面的指标,相关数据采集包括:MinorGC的持续时间、统计MinorGC的次数、FullGC的最差持续时间、最差情况下,FullGC的频率。
如上图,Minor GC的平均持续时间0.069秒,MinorGC的频率为0.389秒一次。
**新生代空间越大,Minor GC的GC时间越长,频率越低。**如果想减少其持续时长,就需要减少其空间大小。如果想减小其频率,就需要加大其空间大小。
这里以减少了新生代空间10%的大小,来减小延迟时间。在此过程中,应该保持老年代和持代的大小不变化。调优后的参数如下变化:
-Xms359m -Xmx359m
-Xmn126m
-XX:PermSize=5m -XX:MaxPermSize=5m
吞吐量调优主要是基于应用程序的吞吐量要求而来的,应用程序应该有一个综合的吞吐指标,这个指标基于整个应用的需求和测试而衍生出来的。
评估当前吞吐量和目标差距是否巨大,如果在20%左右,可以修改参数,加大内存,再次从头调试,如果巨大就需要从整个应用层面来考虑,设计以及目标是否一致了,重新评估吞吐目标。
对于垃圾收集器来说,提升吞吐量的性能调优的目标就是尽可能避免或者很少发生FullGC或者Stop-The-World压缩式垃圾收集(CMS),因为这两种方式都会造成应用程序吞吐降低。尽量在MinorGC 阶段回收更多的对象,避免对象提升过快到老年代。
借助GCViewer日志分析工具,可以非常直观地分析出待调优点。可从以下几方面来分析:
Memory,分析Totalheap、Tenuredheap、Youngheap内存占用率及其他指标,理论上内存占用率越小越好;
Pause,分析Gc pause、Fullgc pause、Total pause三个大项中各指标,理论上GC次数越少越好,GC时长越小越好;
参考文献:
通过这些参数可以对JVM的内存分配做调整
Xms
英文解释:Initial heap size(in bytes)
中文释义:堆区初始值
使用方法:-Xms2g
或 -XX:InitialHeapSize=2048m
Xmx
英文解释:Maximum heap size(in bytes)
中文释义:堆区最大值
使用方法:-Xmx2g
或 -XX:MaxHeapSize=2048m
Xmn
英文解释:Maximum new generation size(in bytes)
中文释义:新生代最大值
使用方法:-Xmn512m
或 -XX:MaxNewSize=512m
PermSize(JDK1.8以后已废弃)
英文解释:Initial size of permanent generation(in bytes)
中文释义:永久代初始大小
使用方法:-XX:PermSize=128m
MaxPermSize(JDK1.8以后已废弃)
英文解释:Maximum size of permanent generation(in bytes)
中文释义:永久代最大值
使用方法:-XX:MaxPermSize=256m
MetaspaceSize(JDK1.8以后用于替换PermSize)
英文解释:Initial size of Metaspaces (in bytes)
中文释义:元数据区初始大小
使用方法:-XX:MetaspaceSize=128m
MaxMetaspaceSize(JDK1.8以后用于替换MaxPermSize)
英文解释:Maximum size of Metaspaces (in bytes)
中文释义:元数据区最大值
使用方法:-XX:MaxMetaspaceSize=256m
Xss
英文解释:Thread Stack Size(in Kbytes)
中文释义:线程栈最大值
使用方法:-Xss256k
或 -XX:ThreadStackSize=256k
MaxDirectMemorySize
英文解释:Maximum total size of NIO direct-buffer allocations
中文释义:最大直接内存(堆外)大小
使用方法:-XX:MaxDirectMemorySize=256m
通过这些参数可以对JVM的GC性能进行调优
NewRatio
英文解释:Ratio of old/new generation sizes
中文释义:老年代和新生代的比值
使用方法:-XX:NewRatio=2
使用经验:假如设为2,则表示老年代最大内存占堆最大内存的2/3,新生代则为1/3。如果设置了Xmn或者NewSize/MaxNewSize,那么NewRatio配置无效
SurvivorRatio
英文解释:Rato of eden/survivor space size
中文释义:新生代中eden区和survivor区的比值
使用方法:-XX:SurvivorRatio=6
使用经验:假如设为6,则表示每个survivor区跟eden区的比值为1:6,每个survivor区占新生代的八分之一
PretenureSizeThreshold
英文解释:Maximum size in bytes of objects allocated in DefNew generation;zero means no maximum
中文释义:可以在新生代直接分配的对象最大值,0表示没有最大值
使用方法:-XX:PretenureSizeThreshold=1000000
使用经验:设置该参数,可以使大于这个值的对象直接在老年代分配,避免在Eden区和Survivor区发生大量的内存复制,该参数只对Serial和ParNew收集器有效,Parallel Scavenge并不认识该参数
MaxTenuringThreshold
英文解释:Maximum value fo tenuring threshold
中文释义:年轻代最大年龄
使用方法:-XX:MaxTenuringThreshold=10
使用经验:每个对象在坚持过一次Minor GC之后,年龄就增加1,当超过这个参数值时就进入老年代,最大支持15
UseSerialGC
英文解释:Use the Serial garbage collector
中文释义:年轻代使用Serial垃圾收集器
使用方法:
开启 -XX:+UseSerialGC
使用经验:不推荐使用,性能太差,老年代将会使用SerialOld垃圾收集器
UseParNewGC
英文解释:Use parallel threads in the new generation
中文释义:年轻代使用ParNew垃圾收集器
使用方法:
开启 -XX:+UseParNewGC
ParallelGCThreads
英文解释:Number of parallel threads parallel gc will use
中文释义:并行执行gc的线程数
使用方法:-XX:ParallelGCThreads=16
UseParallelGC
英文解释:Use the Parallel Scavenge garbage collector
中文释义:年轻代使用Parallel Scavenge垃圾收集器
使用方法:
开启 -XX:+UseParallelGC
使用经验:Linux下1.6,1.7,1.8默认开启,老年代将会使用SerialOld垃圾收集器
UseParallelOldGC
英文解释:Use the Parallel Old garbage collector
中文释义:年轻代使用Parallel Scavenge收集器
使用方法:
开启 -XX:+UseParallelOldGC
使用经验:老年代将会使用Parallel Old收集器
UseConcMarkSweepGC
英文解释:Use Concurrent Mark-Sweep GC in the old generation
中文释义:老年代使用CMS收集器(如果出现"Concurrent Mode Failure",会使用SerialOld收集器)
使用方法:
开启 -XX:+UseConcMarkSweepGC
使用经验:年轻代将会使用ParNew收集器
CMSInitiatingOccupancyFraction
英文解释:Percentage CMS generation occupancy to start a CMS collection cycle. A negative value means that CMSTriggerRatio is used
中文释义:触发执行CMS回收的当前年代区内存占用的百分比,负值表示使用CMSTriggerRatio设置的值
使用方法:-XX:CMSInitiatingOccupancyFraction=75
使用经验:该参数需配合UseCMSInitiatingOccupancyOnly一起使用
UseCMSInitiatingOccupancyOnly
英文解释:Only use occupancy as a criterion for staring a CMS collection
中文释义:只根据占用情况作为开始执行CMS收集的标准,默认关闭
使用方法:
开启 -XX:+UseCMSInitiatingOccupancyOnly
UseCMSCompactAtFullCollection
英文解释:Use Mark-Sweep-Compact algorithm at full collections
中文释义:使用CMS执行Full GC时对内存进行压缩,默认关闭
使用方法:
开启 -XX:+UseCMSCompactAtFullCollection
CMSFullGCsBeforeCompaction
英文解释:Number of CMS full collection done before compaction if > 0
中文释义:多少次FGC后进行内存压缩
使用方法:-XX:CMSFullGCsBeforeCompaction=1
CMSClassUnloadingEnabled
英文解释:Whether class unloading enabled when using CMS GC
中文释义:当使用CMS GC时是否启用类卸载功能,默认关闭
使用方法:
开启 -XX:+CMSClassUnloadingEnabled
CMSParallelRemarkEnabled
英文解释:Whether parallel remark enabled (only if ParNewGC)
中文释义:是否启用并行标记(仅限于ParNewGC),默认关闭
使用方法:
开启 -XX:+CMSParallelRemarkEnabled
UseG1GC
英文解释:Use the Garbage-First garbage collector
中文释义:使用G1垃圾收集器
使用方法:
开启 -XX:+UseG1GC
MaxGCPauseMillis
英文解释:Adaptive size policy maximum GC pause time goal in millisecond, or (G1 Only) the maximum GC time per MMU time slice
中文释义:自适应大小策略的最大GC暂停时间目标(以毫秒为单位),或(仅G1)每个MMU时间片的最大GC时间
使用方法:-XX:MaxGCPauseMillis=200
DisableExplicitGC
英文解释:Ignore calls to System.gc()
中文释义:禁用System.gc()触发FullGC
使用方法:
开启 -XX:+DisableExplicitGC
PS:不建议开启,如果开启了这个参数可能会导致堆外内存无法及时回收造成内存溢出
通过这些参数可以对JVM的GC日志输出进行配置,方便分析
Xloggc
英文解释:GC log file
中文释义:GC日志文件路径
使用方法:-Xloggc:/data/gclog/gc.log
UseGCLogFileRotation
英文解释:Rotate gclog files(for long running applications). It requires -Xloggc:
中文释义:滚动GC日志文件,须配置Xloggc
使用方法:
开启 -XX:+UseGCLogFileRotation
NumberOfGCLogFiles
英文解释:Number of gclog files in rotation(default:0,no rotation)
中文释义:滚动GC日志文件数,默认0,不滚动
使用方法:-XX:NumberOfGCLogFiles=4
GCLogFileSize
英文解释:GC log file size,requires UseGCLogFileRotation. Set to 0 to only trigger rotation via jcmd
中文释义:GC文件滚动大小,需配置UseGCLogFileRotation,设置为0表示仅通过jcmd命令触发
使用方法:-XX:GCLogFileSize=100k
PrintGCDetails
英文解释:Print more details at garbage collection
中文释义:GC时打印更多详细信息,默认关闭
使用方法:
开启 -XX:+PrintGCDetails
可以通过jinfo -flag [+|-]PrintGCDetails
或 jinfo -flag PrintGCDetails=
来动态开启或设置值
PrintGCDateStamps
英文解释:Print date stamps at garbage collection
中文释义:GC时打印时间戳信息,默认关闭
使用方法:
开启 -XX:+PrintGCDateStamps
可以通过jinfo -flag [+|-]PrintGCDateStamps
或 jinfo -flag PrintGCDateStamps=
来动态开启或设置值
PrintTenuringDistribution
英文解释:Print tenuring age information
中文释义:打印存活实例年龄信息,默认关闭
使用方法:
开启 -XX:+PrintTenuringDistribution
PrintGCApplicationStoppedTime
英文解释:Print the time of application has been stopped
中文释义:打印应用暂停时间,默认关闭
使用方法:
开启 -XX:+PrintGCApplicationStoppedTime
PrintHeapAtGC
英文解释:Print heap layout before and after each GC
中文释义:GC前后打印堆区使用信息,默认关闭
使用方法:
开启 -XX:+PrintHeapAtGC
通过这些参数可以在JVM异常情况下执行某些操作,以保留现场做分析用
HeapDumpOnOutOfMemoryError
英文解释:Dump heap to file when java.lang.OutOfMemoryError is thrown
中文释义:抛出内存溢出错误时导出堆信息到指定文件,默认关闭
使用方法:
开启 -XX:+HeapDumpOnOutOfMemoryError
可以通过jinfo -flag [+|-]HeapDumpOnOutOfMemoryError
或 jinfo -flag HeapDumpOnOutOfMemoryError=
来动态开启或设置值
HeapDumpPath
英文解释:When HeapDumpOnOutOfMemoryError is on, the path(filename or directory) of the dump file(defaults to java_pid
中文释义:当HeapDumpOnOutOfMemoryError开启的时候,dump文件的保存路径,默认为工作目录下的java_pid
使用方法:-XX:HeapDumpPath=/data/dump/jvm.dump
使用经验:除非必要,建议不设置
OmitStackTraceInFastThrow
英文解释:Omit backtraces for some ‘hot’ exceptions in optimized code
中文释义:在优化代码里面忽略热点异常回溯
使用方法:
关闭 -XX:-OmitStackTraceInFastThrow
使用经验:某些热点异常抛的太多的话,JVM默认会做优化,会使用JVM初始化的时候创建的异常代替实际的异常,这些异常是没有异常栈信息的,不方便定位问题,如果有碰到这种情况,可以考虑关闭这个配置
通过这些参数可以对JVM进行性能优化或者排查定位问题
server
英文解释:server mode
中文释义:使用服务端模式
使用方法:-server
TieredCompilation
英文解释:Enable tiered compilation
中文释义:启用多层编译
使用方法:
开启 -XX:+TieredCompilation
关闭 -XX:-TieredCompilation
使用经验:java 1.8默认开启分层编译,该参数无效
NativeMemoryTracking
英文解释:Native memory tracking options
中文释义:开启本机内存追踪
使用方法:
开启详细信息 -XX:NativeMemoryTracking=detail
开启概要信息 -XX:NativeMemoryTracking=summary
使用经验:开启的话,大概会增加5%-10%的性能消耗
UnlockDiagnosticVMOptions
英文解释:Enable normal processing of flags
中文释义:解锁对JVM进行诊断的选项参数,默认关闭
使用方法:
开启 -XX:+UnlockDiagnosticVMOptions
PrintNMTStatistics
英文解释:Print native memory tracking summary data if it is on
中文释义:在jvm shutdown的时候输出整体的native memory统计,默认关闭
使用方法:
开启 -XX:+PrintNMTStatistics
使用经验:必须配合参数-XX:+UnlockDiagnosticVMOptions使用,并且只能加在其后才能生效
UseAdaptiveSizePolicy
英文解释:Use adaptive generation sizing policies
中文释义:使用自适应分代内存策略
使用方法:
开启 -XX:+UseAdaptiveSizePolicy
关闭 -XX:-UseAdaptiveSizePolicy
使用经验:1.7以后默认会开启该参数,如果使用CMS回收算法,则会关闭该参数,该参数开启以后会使SurvivorRatio参数失效,如果显示指定了SurvivorRatio,需要关闭该参数
参考文献:
https://docs.oracle.com/en/java/javase/11/tools/java.html#GUID-3B1CE181-CD30-4178-9602-230B800D4FAE
own的时候输出整体的native memory统计,默认关闭使用方法: 开启
-XX:+PrintNMTStatistics`
使用经验:必须配合参数-XX:+UnlockDiagnosticVMOptions使用,并且只能加在其后才能生效
Use adaptive generation sizing policies
使用自适应分代内存策略
-XX:+UseAdaptiveSizePolicy
-XX:-UseAdaptiveSizePolicy
参考文献:
https://docs.oracle.com/en/java/javase/11/tools/java.html#GUID-3B1CE181-CD30-4178-9602-230B800D4FAE