新⽣代的收集器包括:
- Serial
- PraNew
- Parallel Scavenge
⽼年代的收集器包括:
- Serial Old
- Parallel Old
- CMS
回收整个Java堆(新⽣代和⽼年代)
- G1收集器
Serial收集器
如同它的名字(串行),它是一个单线程工作的收集器,使用一个处理器或一条收集线程去完成垃圾收集工作。并且进行垃圾收集时,必须暂停其他所有工作线程,直到垃圾收集结束——这就是所谓的“Stop The World”。
ParNew收集器
ParNew收集器实质上是Serial收集器的多线程并行版本,使用多条线程进行垃圾收集。
Parallel Scavenge收集器
Parallel Scavenge收集器是新⽣代并⾏收集器,追求⾼吞吐量,⾼效利⽤ CPU。
该收集器的⽬标是达到⼀个可控制的吞吐量(Throughput),就是CPU用于运行用户代码的时间和总消耗时间的比值,比值越大,说明垃圾收集的占比越小。
Serial Old收集器
Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记-整理算法。
Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现。
CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,同样是老年代的收集器,采用标记-清除算法。
G1收集器
Garbage First(简称G1)收集器是垃圾收集器的一个颠覆性的产物,它开创了局部收集的设计思路和基于Region的内存布局形式。
CMS收集器
GC过程
可分为4个步骤
- 初始标记(STW)
初始标记会标记GCRoots直接关联的对象以及年轻代指向老年代的对 象,初始标记这个过程会发生Stop the word。但是这个阶段的速度很快,因为没有向下追溯,即只标记一层。(只标记GCRoots直接关联的对象)
- 并发标记(最耗时)
这个过程不会停止用户线程(即不会发生stop the world),这一阶段主要是GC Roots向下追溯,标记所有可达的对象,该阶段比较耗时,因为需要追溯
- 重新标记(STW)
在并发标记阶段,用户线程未停止,可能会产生垃圾对象,所以在这个阶段,要再次进入Stop the World阶段,重新标记下在第二阶段里新创建的一些对象,还有一些已有对象可能失去引用变成垃圾的情况。重新标记的阶段只是对变动过的少数对象进行标记,是速度很快的
- 并发清除
该阶段不会发生stop the world,用户线程一边执行,GC线程一边在回收不可达对象
PS:这个过程可能存在用户线程在不断产生垃圾,但也只能留到下一次GC进行处理,这些垃圾又称为"浮动垃圾"
CMS缺点
- 空间需要预留
CMS垃圾收集器可以一边回收垃圾,一边处理用户线程,那需要在这个过程中保证有充足的内存空间供用户使用。如果CMS运行过程中预留的空间不够用,会报错,这时会启动Serial Old垃圾收集器进行老年代的垃圾回收,会导致停顿的时间很长。
- 内存碎片问题
CMS本质上是实现了标记清除算法的收集器,这意味着会产生内存碎片,由于碎片太多,又可能导致内存空间不足所触发full GC,CMS一般会触发full GC这个过程堆碎片进行整理。整理涉及到【移动】和【标记】,这个过程肯定会stop the world,如果内存足够大,这个过程卡顿也需要一定的时间。
G1垃圾回收器
原理
G1垃圾回收器是一种基于区域的垃圾回收器。其工作原理如下:
- 将堆空间划分为多个相同大小的区域。
- 在每个区域中,将存活对象和垃圾对象进行标记。
- 对于存活对象所占用的内存空间,将其拷贝到空闲的区域中,同时更新其原始引用。
- 最后清除所有垃圾对象,释放内存空间以供再次使用。
GC过程
可分为4个步骤
- 初始标记
标记了从GC Root开始直接关联可达的对象。STW(Stop the World)执行。这个阶段需要Stop the world停顿线程,但耗时很短,而且是借用进行Minor GC的时候同步完成的
- 并发标记
和用户线程并发执行,从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象、
- 最终标记
会STW,标记再并发标记过程中产生的垃圾。
- 筛选回收
制定回收计划,选择多个Region 构成回收集,把回收集中Region的存活对象复制到空的Region中,再清理掉整个旧 Region的全部空间。需要STW。
三色标记算法
- 实现原理
三色标记算法是由集合set实现的。三个集合分别为白,灰,黑集合;
白色集合
白色集合是已死对象的集合,集合内的对象在标记环节结束后将被清除回收。
灰色集合
灰色集合,灰色对象的集合,灰色的对象代表其被根可达的黑色对象引用,但是还没有扫描该灰色对象是否引用白色集合中的对象;因为灰色对象根可达,它不能被回收,而且所有灰色的对象在被垃圾回收器扫描后将被迁移到黑色集合。
黑色集合
黑色集合,黑色对象的集合,黑色对象代表其根可达,是存活的对象,不可以被回收;黑色对象没有引用指向白色对象,只能指向灰色对象
面试题
有了CMS,为什么还要引入G1?
G1主要解决了内存碎片过多的问题。
优点:CMS最主要的优点---并发收集、低停顿。
缺点:CMS同样有三个明显的缺点。
- Mark Sweep算法会导致内存碎片比较多
- CMS的并发能力比较依赖于CPU资源,并发回收时垃圾收集线程可能会抢占用户线程的资源,导致用户程序性能下降。
- 并发清除阶段,用户线程依然在运行,会产生所谓的理“浮动垃圾”(Floating Garbage),本次垃圾收集无法处理浮动垃圾,必须到下一次垃圾收集才能处理。如果浮动垃圾太多,会触发新的垃圾回收,导致性能降低。
你们线上用的什么垃圾收集器?为什么要用它?
jdk8 默认 Parallel Scavenge + Parallel Old,
可以说
采用Parallel New+CMS的组合,我们比较关注服务的响应速度,所以采用了CMS来降低停顿时间。
或者一步到位:
我们线上采用了设计比较优秀的G1垃圾收集器,因为它不仅满足我们低停顿的要求,而且解决了CMS的浮动垃圾问题、内存碎片问题。
垃圾收集器应该如何选择?
- Serial :如果应用程序有一个很小的内存空间(大约100 MB)亦或它在没有停顿时间要求的单线程处理器上运行。
- Parallel:如果优先考虑应用程序的峰值性能,并且没有时间要求要求,或者可以接受1秒或更长的停顿时间。
- CMS/G1:如果响应时间比吞吐量优先级高,或者垃圾收集暂停必须保持在大约1秒以内。
- ZGC:如果响应时间是高优先级的,或者堆空间比较大。