Serial收集器
应用于新生代的单线程的垃圾回收器,在收集垃圾的时候,会出现STW,暂停所有的用户线程。
ParNew收集器
应用于新生代的多线程的垃圾回收器,在收集垃圾的时候,也会出现STW,但是收集垃圾的GC线程可以有多个,在JDK9之后,ParNew收集器只能与CMS配合使用,在JDK9之前,ParNew还能和Serial Old配合使用。
Parallel Scavenge 收集器
也是应用于新生代的多线程的垃圾回收器,但是停顿时间和吞吐量是可以通过参数来控制的,JDK8中默认是Parallel Scavenge + Parallel Old的组合。
Serial Old收集器
应用于老年代的单线程的垃圾回收器,在JDK5之前与Parallel Scavenge收集器配合使用,并且是CMS垃圾收集器发生失败时的后备方案。
Parallel Old收集器
应用于老年代的多线程的垃圾回收器,一般是配合Parallel Scavenge使用。
CMS收集器
应用于老年代的多线程的垃圾回收器,但是之前的多线程回收器仅仅是GC线程是多线程的,而CMS垃圾回收器能让GC线程与用户线程一起运作。它是一款以获取最短回收停顿时间为目标的垃圾回收器,整体分为四个步骤:
- 1.初始标记,标记作为GC Roots的对象,会发生STW,但是时间很短
- 2.并发标记,从GC Roots开始向下遍历对象图,这个阶段耗时长,但是不会发生STW,顶多会造成用户感觉系统卡顿,在这个阶段为了防止“对象消除”,采用了“增量更新”,如果添加了一条存活对象到未扫描对象的引用的时候,会把该引用记录下来
- 3.重新标记,把记录下来的引用重新扫描一遍,更正标记,这个阶段耗时很短,会发生STW
- 4.并发清除,清除没被标记对象,不会发生STW
因为GC线程和用户线程是一起运行的,所以在标记的时候,用户线程也会产生对象,所以要预留一部分空间存放新产生的对象,在JDK6中,默认老年代空间被占用92%就会触发GC,但是如果剩下的8%存不下新产生的对象,就会出现并发异常,就会发生STW,垃圾回收工作交由Serial Old去完成,会导致停顿时间非常长。但是触发GC的阈值是可以通过参数控制的,可以根据实际应用情况来权衡设置。
因为CMS是使用的标记-清楚算法,那多次GC之后会产生很多的碎片,可以设置一个参数来控制每隔多少次GC之后,下次GC之前会先进行碎片整理。
G1收集器
多线程的垃圾回收器,新生代,老年代都可以用,它把堆划分为Region,每隔Region可以是新生代,也可以是老年代,另外还有个Humongous区域专门存放特别大的对象(当这个对象的大小超过Region大小的一半时会被认定为大对象),G1收集器在用户规定的停顿时间内,会优先回收性价比较高的Region,及可回收的大小和回收所需要的时间的比例大的优先回收。后台是有一个优先级列表的。垃圾回收整体分为四个步骤(与CMS相同的部分就不做说明了):
1.初始标记
2.并发标记:与CMS不同的是,为了防止“对象消失”,采用了“原始快照”法,记录了已经被垃圾回收器访问过但是至少还存在一个引用没被扫描过的对象到没被扫描过的对象之间的引用被删除的记录,在最终标记阶段更正
3.最终标记
4.筛选回收:对每个Region回收性价比进行排序,然后指定回收计划
每个Region还留了两个TAMS指针,把Region中的一部分空间划分出来用于并发回收过程中的新对象分配,并发回收时新分配的对象的地址必须要在这两个指针位置上,与CMS相同的是,如果回收速度赶不上内存分配的速度,G1收集器也会冻结用户线程的执行,产生长时间的STW