仅限于Hotspot
0x01 分代GC
- 年轻代:堆区的一部分,对象生命周期很短,所以很适合频率较高的GC。分为2个Survivaor和1个Eden区,默认大小比例1:1:8。
- 老年代:堆区的一部分,对象生命周期较长,适合缓慢的GC频率。
- 永久代:jdk1.7之前用来实现方法区,用来存储字符串常量池、静态变量、类数据等。jdk1.7中把字符串常量池挪到了堆区中,方法区的其他部分还是用永久代来实现。jdk1.8中正式删除永久代,转而提供了一个MetaSpace来存储方法区数据。这里面的对象存活周期都很长。
老项目神雕使用的是ParNew+CMS的组合,基本上是jdk1.8之前的标配。
0x02 回收算法
- 标记-清除:标记可回收的对象,然后回收这些对象的内存。缺点效率不高,且有内存碎片问题。
- 标记-整理:标记可回收的对象,然后将存活对象聚集到一起。优点没有内存碎片问题,缺点效率仍然很低。
- 复制算法:内存空间分为两部分,每次使用其中一块,使用完将存活对象拷贝到另外一块空间。优点效率高,缺点空间利用率低。
- 引用计数:分配和引用计数值+1,删除引用计数值-1,计数值为0的时候释放内存。优点效率高,缺点很难解决循环引用的问题。
《垃圾回收的算法与实现》这本书对GC算法做了很好的讲解。 G1中标记阶段使用的是SATB算法(Snapshot-At-The-Beginning),这个算法基于三色标记算法,它的大概思想就是在GC开始时对堆内存做一个快照,在GC过程中产生的新对象都认为是存活的对象,如果有老对象的引用被删除,也认为这个老对象是存活的。这个算法的优点是效率高,缺点是存在浮动垃圾。
0x03 G1 GC
G1垃圾回收器也是分代GC,不同的是这个垃圾回收器将堆区划分为若干Region,年轻代老年代各占据若干个Region,并且在内存空间中并不连续,在回收的时候选择收益较高的Region进行复制算法的回收。
- Young GC: 选择年轻代的Region作为CSet,遍历这些Region中的RSet,标记存活的对象,然后回收。
- Mixed GC: 根据MaxGCPauseMills设置的参数和Global标记的结果选择几个Region再加上年轻代的所有Region进行一次GC。
- Full GC: 如果对象分配失败,则进行一次FullGC,这个就要用到Serial Old垃圾回收器了。
- 标记周期阶段:初始标记、根区域扫描阶段、并发标记阶段、重新标记阶段、清理阶段(清理空闲Region)。
调优参数在垃圾优先型垃圾回收器调优这篇博文中都有描述。