垃圾收集器
目前常用的有七种垃圾收集器,分别为:
① Serial 收集器(复制算法,新生代,单线程): 它是新生代单线程收集器,采用的复制算法,它在进行垃圾收集时,必须暂停其他所有线程(stop the world)。优点是简单高效。
② ParNew 收集器(复制算法,新生代,多线程,配合CMS): 它是新生代多线程收集器,采用的复制算法,是 Serial 收集器的多线程版本。 可以与 CMS 收集器配合工作。
③ Parallel Scavenge 收集器(复制算法,新生代,多线程,侧重吞吐量): 它是新生代多线程收集器,也是并行的收集器,采用的复制算法。侧重点是吞吐量,可以设置参数来调整吞吐量的大小。吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)。
并行(Parallel): 指多条垃圾收集线程并行工作,而用户线程处于等待状态。并发(Concurrent): 指垃圾收集线程与用户线程并发执行。
④ Serial Old 收集器(标记整理算法,老年代,单线程): 它是老年代单线程收集器,是 Serial 收集器的老年代版本,采用的标记整理算法。⑤ Parallel Old 收集器(标记整理算法,老年代,多线程): 它是老年代多线程收集器,是 Parallel Scavenge 收集器的老年代版本,采用的标记整理算法。在注重吞吐量以及CPU资源敏感的场合,可以优先考虑 Parallel Scavenge 加 Parallel Old 收集器。⑥ CMS(Concurrent Mark Sweep) 收集器(标记清除算法,老年代,并发): 它是一种老年代收集器,采用的标记清除算法,以最短回收停顿时间为目标,适合在注重用户体验的应用上使用。它的运作过程分为四个步骤:
初始标记: 暂停其他所有线程, 并标记 GC Root 能够关联到的对象。并发标记: 同时开启 GC 和用户线程,从GC Root 开始 对堆中对象进行可达性分析,与用户程序并发执行。重新标记: 暂停其他所有线程,修正并发标记期间因用户程序继续运行而导致标记产生变动的那部分对象的标记记录。并发清除: 开启用户线程,同时 GC 线程对标记的区域做清扫。CMS 收集器的优点: 并发收集、低停顿CMS 收集器的缺点: ① 对CPU资源敏感,由于并发标记和并发清除是和用户线程并发执行的,所以会导致用户程序变慢,总的吞吐量降低。 ② 无法处理浮动垃圾,浮动垃圾指的是在CMS并发清理阶段,用户线程还在继续运行,所以会有新的垃圾不断产生,这部分垃圾出现在标记过程之后,所以CMS无法在当次收集中处理掉它们,只能等到下次GC时处理,这部分垃圾就被称为浮动垃圾。 ③ 采用的标记清除算法,会产生大量的空间碎片。
⑦ G1(Garbage-First) 收集器(分代收集算法,并发): 它是唯一一个既能用于新生代又能用于老年代的垃圾收集器,它将Java堆划分为多个大小相等的独立区域(Region),并维护了一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region,把内存化整为零。(但一个对象分配在某个 Region 中,并非只能被这个 Region 中的对象引用,而是可以和整个Java堆中任意的对象发生引用。那在做可达性判定确定对象是否存活时,就又要进行全堆扫描,为了避免这个问题,采用每一个 Region 用一个 Remembered Set 来记录引用关系,避免可达性分析阶段的全堆扫描)它的运作过程分为四个步骤:
初始标记: 暂停其他所有线程, 并标记 GC Root 能够关联到的对象。(和CMS相似)并发标记: 同时开启 GC 和用户线程,从GC Root 开始 对堆中对象进行可达性分析,与用户程序并发执行。(和CMS相似)最终标记: 暂停其他所有线程,修正并发标记期间因用户程序继续运行而导致标记产生变动的那部分对象的标记记录。筛选回收: 它对每个 Region 的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。 G1的特点:
并发性强分代收集空间整合: G1从整体上看是基于标记整理算法实现的收集器,从局部(两个Region)上看是基于复制算法实现的,它们都不会产生内存空间碎片,这是G1相对于CMS的一大优势。可预测的停顿: 这是G1相对于CMS的另一大优势。G1除了像CMS那样追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不能超过N毫秒。(G1的这两大优势就是它和CMS收集器的区别)
JDK1.7和1.8 默认的垃圾收集器是:Parallel Scavenge(新生代)+Parallel Old(老年代)
JDK1.9 默认的垃圾收集器是:G1 收集器