一、查看服务器项目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的堆栈,用于存放栈帧、局部变量等,一般可以根据应用情况适当缩小该值。
未完待续.....
来源:oschina
链接:https://my.oschina.net/xiaozhiwen/blog/3213362