关于JVM调优的那些事
前言:从不生产理论,只做理论的搬运工。本篇理论来源:https://tech.meituan.com/2017/12/29/jvm-optimize.html
GC优化不能解决一切性能问题,它是最后的调优手段。
基本思路
CPU使用率较高,频繁地进行GC且GC时间长。那么我们就需要进行JVM调优,尽可能使每一次GC回收更多的对象。
这里又可以分为两小块进行讨论:
①MinorGC,年轻代的内存使用率始终在高位,频繁的GC但是效率又不高,说明对象没有这么快被回收,活跃的数据量比较大,可以适当把年轻代调大一点。
②Full GC(Full= Minor+Major,通常来说是这么理解,看使用的是什么垃圾回收器),如果每次GC后,内存的使用率还是没有降下来,可以考虑是内存泄漏了;如果GC后内存使用率降下来了,说明年老代的空间不够,还需要调大一点。
具体的调优步骤
调优之前,是不是得把JVM的常用参数在熟悉一下?如果你经常干这个,那就请直接跳过吧。
堆设置
-
-Xms:初始堆大小
-
-Xmx:最大堆大小
-
-XX:NewSize=n:设置年轻代大小
-
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-
-XX:MaxPermSize=n:设置持久代大小
收集器设置
-
-XX:+UseSerialGC:设置串行收集器
-
-XX:+UseParallelGC:设置并行收集器
-
-XX:+UseParalledlOldGC:设置并行年老代收集器
-
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-
-XX:+PrintGC
-
-XX:+PrintGCDetails
-
-XX:+PrintGCTimeStamps
-
-Xloggc:filename
并行收集器设置
-
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
并发收集器设置
-
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。
JVM中各分区的大小对GC的性能影响很大。那么要如何设计各分区的大小呢,分析活跃数据大小是很好的切入点。
这里呢,我们不用纠结该怎么分配比例了, 美团技术大佬给我们总结了,如下表:
空间 | 倍数 |
---|---|
总大小 | 3-4 倍活跃数据的大小 |
新生代 | 1-1.5 活跃数据的大小 |
老年代 | 2-3 倍活跃数据的大小 |
永久代 | 1.2-1.5 倍Full GC后的永久代空间占用 |
例如:我们的活跃数据是300M,那么我们的Heap总大小就应该是300M*4=1200M;新生代:300M*1.5=450M;老年代:1200M-450M=750M。当然这个具体的大小可以根据自己应用程序的特性进行调整。
垃圾收集器的选择
好了,确定了各个分区大小后,就是确定要使用的垃圾收集器了。JVM的内存模型决定了垃圾回收是分代进行的,其中,由于新生代进行Minor GC后,一般存活的对象较少,可以采用“复制”算法;而年老代存活的对象较多,一般采用“标记-整理”和“标记-清除”算法。
首先看到我们常用的垃圾回收器,如下表:
垃圾回收器 | 特性 |
---|---|
串行(Serial)回收器 | 单线程的一个回收器,简单、易实现、效率高。 |
并行(ParNew)回收器 | Serial的多线程版,可以充分的利用CPU资源,减少回收的时间。 |
吞吐量优先(Parallel Scavenge)回收器 | 侧重于吞吐量的控制 |
并发标记清除(CMS,Concurrent Mark Sweep)回收器 | 以获取最短回收停顿时间为目标的回收器,该回收器是基于“标记-清除”算法实现的。 |
Serial Old | Serial Old是Serial的老年代版本。同Serial一样, 它也是单线程收集器。用的是“标记——整理”算法。 |
Parallel Old | Parallel Old 是 Parallel Scavenge 的老年代版本,使用多线程和“标记——整理算法”。 |
G1(Garbage-First)收集器 | G1 能充分利用多CPU的硬件优势,使用多个CPU来缩短“Stop The World”停顿时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。G1从整体来看是基于“标记-整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,这意味着G1运行期间不会产生内存空间碎片。 |
附上一张简图
看完上面这些,你知道要怎么进行JVM的参数调优了吧。