JVM调优主要就是调整下面两个指标
停顿时间:垃圾收集器做垃圾回收中断应用执行的时间。-XX:MaxGCPauseMillis
吞吐量:吞吐量是指应用程序线程用时占程序总用时的比例。 例如,吞吐量99/100意味着100秒的程序执行时间应用程序线程运行了99秒, 而在这一时间段内GC线程只运行了1秒。
注:垃圾收集的时间和总时间的占比:1/(1+n),吞吐量为1-1/(1+n)。__-XX:GCTimeRatio=n
一、GC调优步骤
1.打印GC日志
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log
注:Tomcat可以直接加载JAVA_OPTS变量里
2.分析日志得到关键性指标
3.分析GC原因,调优JVM参数
二、Parallel Scavenge收集器(默认)
启动eureka服务的gc日志分析
java -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc-parallel.log -jar eureka-server-2.0.2.RELEASE.jar
分析gc-parallel.log
Java HotSpot(TM) 64-Bit Server VM (25.102-b14) for windows-amd64 JRE (1.8.0_102-b14), built on Jun 22 2016 13:15:21 by "java_re" with MS VC++ 10.0 (VS2010)
Memory: 4k page, physical 12493080k(6045448k free), swap 14983448k(6307336k free)
CommandLine flags: -XX:InitialHeapSize=199889280 -XX:MaxHeapSize=3198228480 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
2019-08-10T19:58:47.887+0800: 1.065: [GC (Allocation Failure) [PSYoungGen: 49152K->3312K(57344K)] 49152K->3320K(188416K), 0.1002477 secs] [Times: user=0.05 sys=0.00, real=0.10 secs]
2019-08-10T19:58:48.382+0800: 1.497: [GC (Allocation Failure) [PSYoungGen: 52464K->4048K(106496K)] 52472K->4064K(237568K), 0.0434123 secs] [Times: user=0.00 sys=0.02, real=0.04 secs]
2019-08-10T19:58:49.279+0800: 2.395: [GC (Allocation Failure) [PSYoungGen: 102352K->4912K(106496K)] 102368K->4936K(237568K), 0.0144670 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
2019-08-10T19:58:50.040+0800: 3.156: [GC (Metadata GC Threshold) [PSYoungGen: 79829K->6304K(204800K)] 79853K->6400K(335872K), 0.0166599 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]
2019-08-10T19:58:50.057+0800: 3.172: [Full GC (Metadata GC Threshold) [PSYoungGen: 6304K->0K(204800K)] [ParOldGen: 96K->6261K(79872K)] 6400K->6261K(284672K), [Metaspace: 20516K->20516K(1067008K)], 0.0517235 secs] [Times: user=0.13 sys=0.02, real=0.05 secs]
2019-08-10T19:58:53.810+0800: 6.925: [GC (Allocation Failure) [PSYoungGen: 196608K->7653K(204800K)] 202869K->13922K(284672K), 0.0099539 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
2019-08-10T19:58:54.599+0800: 7.715: [GC (Allocation Failure) [PSYoungGen: 204261K->8703K(289792K)] 210530K->20812K(369664K), 0.0248190 secs] [Times: user=0.06 sys=0.00, real=0.03 secs]
2019-08-10T19:58:56.013+0800: 9.129: [GC (Allocation Failure) [PSYoungGen: 289791K->13293K(294400K)] 301900K->28482K(374272K), 0.0385212 secs] [Times: user=0.16 sys=0.01, real=0.04 secs]
2019-08-10T19:58:57.993+0800: 11.109: [GC (Allocation Failure) [PSYoungGen: 294381K->17389K(448512K)] 309570K->34338K(528384K), 0.0282796 secs] [Times: user=0.08 sys=0.00, real=0.03 secs]
2019-08-10T19:58:59.202+0800: 12.318: [GC (Metadata GC Threshold) [PSYoungGen: 59097K->17933K(452096K)] 76046K->34890K(531968K), 0.0202485 secs] [Times: user=0.05 sys=0.00, real=0.02 secs]
2019-08-10T19:58:59.223+0800: 12.338: [Full GC (Metadata GC Threshold) [PSYoungGen: 17933K->0K(452096K)] [ParOldGen: 16957K->33158K(147968K)] 34890K->33158K(600064K), [Metaspace: 33942K->33942K(1079296K)], 0.1874046 secs] [Times: user=0.49 sys=0.02, real=0.19 secs]
2019-08-10T19:59:06.796+0800: 19.911: [GC (Allocation Failure) [PSYoungGen: 431104K->6320K(549376K)] 464262K->39486K(697344K), 0.0150792 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]
2019-08-10T19:59:11.410+0800: 24.526: [GC (Allocation Failure) [PSYoungGen: 549040K->13048K(573952K)] 582206K->46222K(721920K), 0.0296726 secs] [Times: user=0.09 sys=0.03, real=0.03 secs]
2019-08-10T20:09:14.424+0800: 627.539: [GC (Allocation Failure) [PSYoungGen: 564472K->14719K(675328K)] 597646K->47902K(823296K), 0.0259811 secs] [Times: user=0.11 sys=0.02, real=0.03 secs]
使用GCeasy可视化分析日志:
调优前
详细结果请看如下链接
https://www.gceasy.io/diamondgc-report.jsp?oTxnId_value=542a04a7-8772-4aa9-aa92-754ce195d4b4
第一次调优,设置Metaspace大小:增大元空间大小-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=64M
https://www.gceasy.io/diamondgc-report.jsp?oTxnId_value=76139c9e-f3c3-446d-b1b9-9f3156c6eeb6
第二次调优,增大年轻代动态扩容增量(默认是20%),可以减少YGC:-XX:YoungGenerationSizeIncrement=30
https://www.gceasy.io/diamondgc-report.jsp?oTxnId_value=76218376-20f7-4778-95a9-69593a02cd5a
比较下几次调优效果:
吞吐量 | 最大停顿 | 平均停顿 | YGC | FGC | |
---|---|---|---|---|---|
99.901% | 190ms | 44.3ms | 14 | 2 | 调优前 |
99.53% | 70ms | 23.3ms | 12 | 0 | 第一次调优 |
98.669% | 80ms | 26.4ms | 11 | 0 | 第二次调优 |
三、配置CMS收集器
-XX:+UseConcMarkSweepGC
分析gc-cms.log
四、配置G1收集器
-XX:+UseG1GC
启动eureka服务的gc日志分析
java -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+UseG1GC -Xloggc:./gc-g1.log -jar eureka-server-2.0.2.RELEASE.jar
分析gc-g1.log
Java HotSpot(TM) 64-Bit Server VM (25.102-b14) for windows-amd64 JRE (1.8.0_102-b14), built on Jun 22 2016 13:15:21 by "java_re" with MS VC++ 10.0 (VS2010)
Memory: 4k page, physical 12493080k(6729568k free), swap 14983448k(6356832k free)
CommandLine flags: -XX:InitialHeapSize=199889280 -XX:MaxHeapSize=3198228480 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC -XX:-UseLargePagesIndividualAllocation
2019-08-10T20:47:49.791+0800: 0.647: [GC pause (G1 Evacuation Pause) (young), 0.1467107 secs]
[Parallel Time: 145.5 ms, GC Workers: 4]
[GC Worker Start (ms): Min: 646.7, Avg: 646.7, Max: 646.7, Diff: 0.0]
[Ext Root Scanning (ms): Min: 0.2, Avg: 15.5, Max: 61.1, Diff: 60.9, Sum: 62.0]
[Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0]
[Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Code Root Scanning (ms): Min: 0.0, Avg: 15.2, Max: 60.4, Diff: 60.4, Sum: 60.7]
[Object Copy (ms): Min: 84.2, Avg: 114.6, Max: 144.9, Diff: 60.6, Sum: 458.5]
[Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Termination Attempts: Min: 1, Avg: 3.0, Max: 4, Diff: 3, Sum: 12]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.0, Sum: 0.2]
[GC Worker Total (ms): Min: 145.4, Avg: 145.4, Max: 145.4, Diff: 0.0, Sum: 581.5]
[GC Worker End (ms): Min: 792.1, Avg: 792.1, Max: 792.1, Diff: 0.0]
[Code Root Fixup: 0.1 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.3 ms]
[Other: 0.8 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.3 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 0.3 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms]
[Eden: 14.0M(14.0M)->0.0B(10.0M) Survivors: 0.0B->2048.0K Heap: 14.0M(192.0M)->2242.0K(192.0M)]
[Times: user=0.00 sys=0.00, real=0.15 secs]
2019-08-10T20:47:50.071+0800: 0.926: [GC pause (G1 Evacuation Pause) (young), 0.0090643 secs]
[Parallel Time: 2.5 ms, GC Workers: 4]
[GC Worker Start (ms): Min: 926.3, Avg: 926.4, Max: 926.4, Diff: 0.0]
[Ext Root Scanning (ms): Min: 0.2, Avg: 0.3, Max: 0.6, Diff: 0.4, Sum: 1.2]
[Update RS (ms): Min: 0.0, Avg: 0.2, Max: 0.4, Diff: 0.4, Sum: 0.7]
[Processed Buffers: Min: 0, Avg: 0.5, Max: 1, Diff: 1, Sum: 2]
[Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.1, Max: 0.6, Diff: 0.6, Sum: 0.6]
[Object Copy (ms): Min: 1.6, Avg: 1.8, Max: 1.9, Diff: 0.4, Sum: 7.3]
[Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Termination Attempts: Min: 1, Avg: 3.3, Max: 6, Diff: 5, Sum: 13]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[GC Worker Total (ms): Min: 2.4, Avg: 2.5, Max: 2.5, Diff: 0.0, Sum: 9.8]
[GC Worker End (ms): Min: 928.8, Avg: 928.8, Max: 928.8, Diff: 0.0]
[Code Root Fixup: 0.1 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.1 ms]
[Other: 6.4 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.2 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 0.1 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms]
[Eden: 10.0M(10.0M)->0.0B(17.0M) Survivors: 2048.0K->2048.0K Heap: 12.2M(192.0M)->4305.5K(384.0M)]
[Times: user=0.00 sys=0.00, real=0.01 secs]
young GC:[GC pause (G1 Evacuation Pause)(young)
initial-mark:[GC pause (Metadata GC Threshold)(young)(initial-mark) (参数:InitiatingHeapOccupancyPercent)
mixed GC:[GC pause (G1 Evacuation Pause)(Mixed) (参数:G1HeapWastePercent)
full GC:[Full GC (Allocation Failure)(无可用region)
注:G1内部,前面提到的混合GC是非常重要的释放内存机制,它避免了G1出现Region没有可用的情况,否则就会触发 FullGC事件。CMS、Parallel、Serial GC都需要通过Full GC去压缩老年代并在这个过程中扫描整个老年代。G1的 Full GC算法和Serial GC收集器完全一致。当一个Full GC发生时,整个Java堆执行一个完整的压缩,这样确保了最大的空余内存可用。G1的Full GC是一个单线程,它可能引起一个长时间的停顿时间,G1的设计目标是减少Full GC__,满足应用性能目标。
查看发生MixedGC的阈值:jinfo -flag InitiatingHeapOccupancyPercent 进程ID调优:
第一次调优,设置Metaspace大小:增大元空间大小-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=64M
第二次调优,添加吞吐量和停顿时间参数:-XX:GCTimeRatio=99 -XX:MaxGCPauseMillis=10
五、JVM内存的参数配置与调优
在通过一张图来了解如何通过参数来控制各区域的内存大小
堆内存的接口和内存限制参数
六、GC常用参数
1.堆栈设置
-Xss:每个线程的栈大小
-Xms:初始堆大小,默认物理内存的1/64
-Xmx:最大堆大小,默认物理内存的1/4
-Xmn:新生代大小
-XX:NewSize:设置新生代初始大小
-XX:MaxNewSize设置新生代最大空间大小
-XX:NewRatio:默认2表示新生代占年老代的1/2,占整个堆内存的1/3。
-XX:SurvivorRatio:默认8表示一个survivor区占用1/8的Eden内存,即1/10的新生代内存。
-XX:PermSize设置永久代最小空间大小
-XX:MaxPermSize设置永久代最大空间大小
-XX:MetaspaceSize:设置元空间大小
-XX:MaxMetaspaceSize:设置元空间最大允许大小,默认不受限制,JVM Metaspace会进行动态扩展。
除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:
-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
注:没有直接设置老年代的参数,但是可以设置堆空间大小和新生代空间大小两个参数来间接控制**老年代空间大小=堆空间大小-年轻代大空间大小_**
2.垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
3.收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:+UseParNewGC:在新生代使用并行收集器
-XX:+UseParalledlOldGC:设置并行老年代收集器
-XX:+UseConcMarkSweepGC:设置CMS并发收集器
-XX:+UseG1GC:设置G1收集器
-XX:ParallelGCThreads:设置用于垃圾回收的线程数
4.并行收集器设置
-XX:ParallelGCThreads:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis:设置并行收集最大暂停时间
-XX:GCTimeRatio:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
5.CMS收集器设置
-XX:+UseConcMarkSweepGC:设置CMS并发收集器
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads:设置并发收集器新生代收集方式为并行收集时,使用的CPU数。并行收集线程数。
-XX:CMSFullGCsBeforeCompaction:设定进行多少次CMS垃圾回收后,进行一次内存压缩
-XX:+CMSClassUnloadingEnabled:允许对类元数据进行回收
-XX:UseCMSInitiatingOccupancyOnly:表示只在到达阀值的时候,才进行CMS回收
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况
-XX:ParallelCMSThreads:设定CMS的线程数量
-XX:CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发
-XX:+UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片的整理
6.G1收集器设置
-XX:+UseG1GC:使用G1收集器
-XX:ParallelGCThreads:指定GC工作的线程数量
-XX:G1HeapRegionSize:指定分区大小(1MB~32MB,且必须是2的幂),默认将整堆划分为2048个分区
-XX:GCTimeRatio:吞吐量大小,0-100的整数(默认9),值为n则系统将花费不超过1/(1+n)的时间用于垃圾收集
-XX:MaxGCPauseMillis:目标暂停时间(默认200ms)
-XX:G1NewSizePercent:新生代内存初始空间(默认整堆5%)
-XX:G1MaxNewSizePercent:新生代内存最大空间
-XX:TargetSurvivorRatio:Survivor填充容量(默认50%)
-XX:MaxTenuringThreshold:最大任期阈值(默认15)
-XX:InitiatingHeapOccupancyPercen:老年代占用空间超过整堆比IHOP阈值(默认45%),超过则执行混合收集
-XX:G1HeapWastePercent:堆废物百分比(默认5%)
-XX:G1MixedGCCountTarget:参数混合周期的最大总次数(默认8)
七、参考资料
jvm系列之内存模型:http://blog.leanote.com/post/zhangyue/jvm%E7%B3%BB%E5%88%97%E4%B9%8B%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B