目录
Parallel Scavenge收集器与ParNew收集器 的区别
各收集器之间的关系
并行(Parallel):并行描述的是多条垃圾收集器线程之间的关系,说明同一时间有多条这样的线 程在协同工作,通常默认此时用户线程是处于等待状态。
·并发(Concurrent):并发描述的是垃圾收集器线程与用户线程之间的关系,说明同一时间垃圾 收集器线程与用户线程都在运行。由于用户线程并未被冻结,所以程序仍然能响应服务请求,但由于 垃圾收集器线程占用了一部分系统资源,此时应用程序的处理的吞吐量将受到一定影响。
一、Serial收集器
Serial收集器是最基础、历史最悠久的收集器。
特点
单线程工作的收集器
在它进行垃圾收集时,必须暂停其他所有工作线程,直到它收集结束(Stop The World)
适用场景
是HotSpot虚拟机运行在客户端模式下的默认新生 代收集器
优点
与其他收集器的单线程相比简单而高效
对于内 存资源受限的环境,它是所有收集器里额外内存消耗最小的;对于单核处理 器或处理器核心数较少的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以 获得最高的单线程收集效率。
二、ParNew收集器
ParNew收集器实质上是Serial收集器的多线程并行版本
成也萧何败也萧何
在JDK 5发布时,HotSpot推出了一款在强交互应用中几乎可称为具有划时代意义的垃圾收集器 ——CMS收集器。这款收集器是HotSpot虚拟机中第一款真正意义上支持并发的垃圾收集器,它首次 实现了让垃圾收集线程与用户线程(基本上)同时工作。
首选的新生代收集器 原因
除了Serial收集器外,目前只有它能与CMS 收集器配合工作。
自JDK 9开始
更先进的G1收集器带着CMS继承者和替代者的光环登场
还取消了ParNew加 Serial Old以及Serial加CMS这两组收集器组合的支持
意味着ParNew和CMS从此只能互相搭配使用
三、Parallel Scavenge收集器
Parallel Scavenge收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能 地缩短垃圾收集时用户线程的停顿时间;
而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐 量。
所谓吞吐量就是处理器用于运行用户代码的时间与处理器总消耗时间的比值
Parallel Scavenge收集器也经常被称作“吞吐量优先收集器”
吞吐量计算公式
Parallel Scavenge收集器与ParNew收集器 的区别
自适应调节策略
四、Serial Old收集器
Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记-整理算法
主要意义
供客户端模式下的HotSpot虚拟机使用
在服务端模式下,它也可能有两种用 途:
一种是在JDK 5以及之前的版本中与Parallel Scavenge收集器搭配使用,
另外一种就是作为CMS 收集器发生失败时的后备预案,在并发收集发生Concurrent Mode Failure时使用。
五、Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实 现,是jdk8中默认的老年代收集器。
吞吐量优先
六、CMS收集器
CMS收集器是一种以获取最短回收停顿时间为目标的收集器,基于标记-清除算法实现的
步骤
1)初始标记(CMS initial mark)
2)并发标记(CMS concurrent mark)
3)重新标记(CMS remark)
4)并发清除(CMS concurrent sweep)
初始标记、重新标记这两个步骤仍然需要“Stop The World”。
初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快;
并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对 象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行
重 新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的 标记记录,这个阶段的停顿时间通常会比初始标记阶段稍长一 些,但也远比并发标记阶段的时间短
并发清除阶段,清理删除掉标记阶段判断的已经死亡的 对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。
CMS回收阶段
CMS收集器的内存回收过程是与用户线程一起并发执行的
CMS优点:并发收集、低停顿
CMS缺点:
1、在并发阶段,它虽然不会导致用户线程停顿,但却会因为占用了一部分线程(或者说处理器的计 算能力)而导致应用程序变慢,降低总吞吐量
2、无法处理“浮动垃圾”
3、着收集结束时会有大量空间碎片产生
在CMS的并发标记和并发清理阶 段,用户线程是还在继续运行的,程序在运行自然就还会伴随有新的垃圾对象不断产生,但这一部分 垃圾对象是出现在标记过程结束以后,CMS无法在当次收集中处理掉它们,只好留待下一次垃圾收集 时再清理掉。这一部分垃圾就称为“浮动垃圾”。
JDK 9后被抛弃
七、Garbage First收集器
Garbage First(简称G1)收集器是垃圾收集器技术发展历史上的里程碑式的成果,它开创了收集 器面向局部收集的设计思路和基于Region的内存布局形式
JDK 9后成为服务端模式下的默认垃圾收集器
停顿时间模型:能够支持指定在一个长度为M毫秒的时间片段 内,消耗在垃圾收集上的时间大概率不超过N毫秒这样的目标,这几乎已经是实时Java(RTSJ)的中 软实时垃圾收集器特征了。
停顿时间模型的实现
G1不再坚持固定大小以及固定数量的 分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以 根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。使用Region划分内存空间,以及具有优先级的区域回收方式,保证了G1收集器在有限的时间内获 取尽可能高的收集效率。
Humongous区域
G1认为只要大小超过了一个 Region容量一半的对象即可判定为大对象
超过了整个Region容量的超级大对象, 将会被存放在N个连续的Humongous Region之中
跨Region引用对象如何解决
每个Region都维护有自己的记忆集,这些记忆集会记录下别的Region 指向自己的指针,并标记这些指针分别在哪些卡页的范围之内
在并发标记阶段如何保证收集线程与用户线程互不干扰地运行
CMS收集器采用增量更新算法实现,而G1 收集器则是通过原始快照(SATB)算法来实现的。
步骤
初始标记(Initial Marking):仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS 指针的值,让下一阶段用户线程并发运行时,能正确地在可用的Region中分配新对象。这个阶段需要 停顿线程,但耗时很短,而且是借用进行Minor GC的时候同步完成的,所以G1收集器在这个阶段实际 并没有额外的停顿。
并发标记(Concurrent Marking):从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆 里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以 后,还要重新处理SATB记录下的在并发时有引用变动的对象。 ·
最终标记(Final Marking):对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留 下来的最后那少量的SATB记录。 ·
筛选回收(Live Data Counting and Evacuation):负责更新Region的统计数据,对各个Region的回 收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region 构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧 Region的全部空间。这里的操作涉及存活对象的移动,是必须暂停用户线程,由多条收集器线程并行 完成的。
G1收集器除了并发标记外,其余阶段也是要完全暂停用户线程的, 换言之,它并非纯粹地追求低延迟,官方给它设定的目标是在延迟可控的情况下获得尽可能高的吞吐 量,所以才能担当起“全功能收集器”的重任与期望
与CMS的比较
优点:
指定最大停顿时间、分Region的内存布局、按收益动 态确定回收集这些创新性设计带来的红利
整体来看是基于“标记-整理”算法实现的收集器,但从局部(两个Region 之间)上看又是基于“标记-复制”算法实现。意味着G1运作期间不会产生内存 空间碎片,垃圾收集完成之后能提供规整的可用内存。
缺点:
G1无论是为了垃圾收集产生的内存占用(Footprint)还是程序运行时的额外执行负载 (Overload)都要比CMS要高。
总结:
目前在小内存应用上CMS的表现大概率仍然要会优于G1,而在大内存应用上G1则大多能发挥其 优势,这个优劣势的Java堆容量平衡点通常在6GB至8GB之间