JVM调优实战分析

|▌冷眼眸甩不掉的悲伤 提交于 2020-04-06 18:14:42

一、查看服务器项目JVM参数以及参数分析

1、jps 命令 : 列出系统中所有的 Java 应用程序以及PID

如下图所示,26647就是我部署在服务器的一个小项目的 PID

2、jmap命令:查看堆的使用情况

如下所示,数据为未调整的默认值

[root@VM_49_159_centos ~]# jmap -heap 26647
Attaching to process ID 26647, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.162-b12

using thread-local object allocation.
Mark Sweep Compact GC

Heap Configuration:    (堆的结构配置)
   MinHeapFreeRatio         = 40    空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.
   MaxHeapFreeRatio         = 70   空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制.
   MaxHeapSize              = 482344960 (460.0MB)       (堆的最大值)
   NewSize                  = 10485760 (10.0MB)   (初始年轻代大小)
   MaxNewSize               = 160759808 (153.3125MB)        (年轻代最大值)
   OldSize                  = 20971520 (20.0MB)        (初始年老代大小)
   NewRatio                 = 2        (年老代 :年轻代  默认是 2:1)
   SurvivorRatio            = 8       ( Survivor区分为from和to两个部分,各占一半,年轻代另外一个区是Eden区,Eden:from 默认为8:1)
   MetaspaceSize            = 21807104 (20.796875MB)        表示metaspace首次使用不够而触发FGC的阈值 ,JDK8之后废除永久代,采用元空间)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)      (压缩类空间,出现java.lang.OutOfMemoryError: Compressed class space可以调大该值)
   MaxMetaspaceSize         = 17592186044415 MB        ( metaspace区域的最大值
   G1HeapRegionSize         = 0 (0.0MB)           ( G1垃圾收集器 Garbage-First Garbage Collector 的region大小)

Heap Usage:    (堆的使用率)
New Generation (Eden + 1 Survivor Space):       年轻代中 Eden区+From区
   capacity = 11075584 (10.5625MB)     容量
   used     = 1421240 (1.3554000854492188MB)     已使用
   free     = 9654344 (9.207099914550781MB)       剩余
   12.832190158099113% used            使用占比
Eden Space:        年轻代中 Eden区
   capacity = 9895936 (9.4375MB)
   used     = 1410936 (1.3455734252929688MB)
   free     = 8485000 (8.091926574707031MB)
   14.257731658733444% used
From Space:      年轻代中Sruvivor的From区
   capacity = 1179648 (1.125MB)
   used     = 10304 (0.00982666015625MB)
   free     = 1169344 (1.11517333984375MB)
   0.8734809027777778% used
To Space:     年轻代中Sruvivor的To区
   capacity = 1179648 (1.125MB)
   used     = 0 (0.0MB)
   free     = 1179648 (1.125MB)
   0.0% used
tenured generation:   年老代
   capacity = 24395776 (23.265625MB)
   used     = 22119176 (21.09449005126953MB)
   free     = 2276600 (2.1711349487304688MB)
   90.66805663406649% used

20026 interned Strings occupying 1919776 bytes.

3、 jstat -gc 命令:查看GC情况

# jstat -gc 26647
 S0C     S1C     S0U    S1U      EC       EU          OC            OU          MC         MU      CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
1152.0 1152.0  10.1   0.0    9664.0   7553.2   23824.0    21600.8   47312.0 45387.3 6140.0 5735.0    434    3.765     2      0.111    3.876

S0C和S1C分别是Survivor两个区的大小,  S0U和S1U分别是Survivor两个区已使用的大小

EC为 Eden Capacity ,EU为 Eden Usage,OC为年老代大小,OU为年老代已使用大小

MC和MU时方法区的大小和已使用大小

CCSC为压缩类空间大小,CCSU压缩类空间已使用大小

YGC为年轻代GC次数,YGCT为YGC总时间

FGC为FullGC次数,FGCT为FGC总时间,GCT为垃圾回收总时间

二、堆内存的简单分析和年轻代分区及GC算法

1、堆内存的简单分析

由于JDK8之后真正废除了永久代,所以堆的主要组成就是 年轻代和年老代了

年轻代又分为 Eden和Survivor区,默认大小是 8:2 ,因为Survivor由两个同等大小的From区和To区组成

为什么Survivor区要分成两个同等大小的呢,这个就关系到年轻代的GC算法----“复制算法”了

2、复制算法简单描述

年轻代的GC算法主要采用复制算法,首先GC开始前,To区是空的。

然后GC开始时,无引用的对象会被回收(目前常用可达性分析算法判断是否存活),存活的会被复制到To区

From区的对象每经过一次MinorGC都会年龄增加一岁,达到阈值的会被复制到年老代中

(阈值可通过 -XX:MaxTenuringThreshold 设置)

没达到阈值的会被复制到To区,经过这次GC后,Eden区和From区就被清空了

接着From区和To区互换角色,继续等待下一次GC

三、JVM调优的目的

对JVM内存的系统级调优主要目的是减少GC的频率和FullGC的次数,因为FullGC会对整个堆进行整理,所以比较慢。因此应该尽可能减少FullGC的次数。

导致FullGC的原因:老年代被写满、持久代空间不足、System.gc() 被调用。

可以通过调整年轻代和年老代的比例来控制GC的次数和时间到一个比较合适的范围,至于怎样才是合适的,需要根据服务器资源性能和项目的情况。

年轻代和年老代默认比例是 1:2, 可以通过调整NewRatio来调整二者的比例,也可以通过调整年轻代的大小来控制。

把年轻代的占比调大了,可以延长MinorGC的周期,但是会增加每次GC的时间。同时也必定会缩小年老代的空间,导致更频繁的FullGC。

把年轻代的占比调小了,可以减少MinorGC的时间,但是会增大GC的频率。同时年老代的空间增大可以减少FullGC的次数。

如果应用存在大量的临时对象,可以选择更大的年轻代,如果存在较多的持久对象,可以选择适当增大年老代。

如果机器性能比较好可以为年老代选择并行收集算法    -XX:+UseParallelOldGC

也可以通过调整栈帧的大小来优化,每个线程默认会开启1M的堆栈,用于存放栈帧、局部变量等,一般可以根据应用情况适当缩小该值。

 

未完待续.....

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!