整理一下关于JVM性能调优的相关知识,不是很全面,是在面试题上看到的
首先谈一谈垃圾回收算法
主要有三种基本算法:标记-清除算法、复制算法、标记压缩算法.
而目前最常用的就是分代收集算法:将Java堆分为新生代和年老代,这样就可以根据各个年代的特点采用适当的算法。
然后要谈的是一次完整的GC流程,对象如何晋升到年老代
- Java堆 = 新生代 + 年老代
- 新生代 = Eden + s0 + s1
- 当Eden满了之后,虚拟机触发一次Minor GC, 已收集新生代的垃圾。存活下来的对象,会被转移到survivor区,大对象(需要大量连粗存储空间的Java对象)直接进入老年态。
- 如果对象在Eden中出生, 并经过一次Minor GC之后仍然存活,并且被survivor容器所容纳的话, 年龄设为1,每熬过一次MInor GC,年龄+1,若年龄超过一定的限制(15),则被晋升到老年态,即长期存活的对象进入老年态。
- 老年态满了无法容纳更多对象,Minor GC之后通常会进行Full GC,Full GC清理整个内存堆,包括年轻代和年老代。
- Major GC 发生在年老代的GC, 清理年老区,经常伴随着至少一次的Full GC ,比Minor GC慢十倍以上。
然后就想说一说导致Full GC的情况
- 新生代设置的过小
一是新生代GC的次数太频繁,增加系统消耗;二是导致大量对象直接进入年老代,占据了年老代的剩余空间,诱发Full GC.。 - 新生代设置的过大
一是新生代设置的过大会导致年老代过小(堆内存容量大小一定),从而诱发Full GC;二是新生代GC消耗的时间大幅度增加。 - survivor设置的过小
导致对象从Eden直接进入年老代 - survivor设置的过大
导致Eden过小,增加了GC的频率。
JVM性能调优
- 设定堆内存大小
- 设置新生代大小
- 设定垃圾回收器:新生代用UseParNewGC;年老代使用UseConMarkSweepGC