前段时间面试一家公司
面试官:JDK8中默认的垃圾回收机制是什么?
答:分代收集(分代不就是针对老年代和新生代有不同的回收方法吗?)
面试官:哼(冷笑了一下,还在看我)
答:。。。(无言以对,难道不是吗?)
以上是背景,刚刚又看了一遍垃圾回收机制和垃圾收集器,我才知道我没有错!!!那他为什么对我冷笑
————————————————————————————————————————————————————
JDK7和JDK8默认的垃圾回收器是:Parallel Scavenge收集器(新生代)和Parallel Old收集器(老年代)
JDK9默认的则是G1收集器,而与它一直做对比的则是CMS收集器。
所以就针对Parallel Scavenge收集器、Parallel Old收集器、G1收集器、CMS收集器进行简单的解释。
Parallel Scavenge收集器
是一个新生代收集器,使用的是复制算法,又是并行的多线程收集器
Parallel Scavenge收集器的特点是它的关注点和其他收集器都不同,CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量。
由于与吞吐量关系密切,所以Parallel Scavenge收集器也经常被称为"吞吐量优先"收集器。
Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法。
CMS收集器
CMS收集器是一种以获取最短回收停顿时间为目标的收集器。是基于标记-清除算法实现的
它的整个运行过程分为四个步骤:
初始标记(CMS initial mark)
并发标记(CMS concurrent mark)
重新标记(CMS remark)
并发清除(CMS concurrent sweep)
其中初始标记、重新标记这两个步骤需要"Stop The World"。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生的变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
因为整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,整体上来说CMS收集器的内存回收过程是与用户线程一起并发执行的。
CMS收集器的优点:
并发收集、低停顿。
CMS收集器的缺点是:
对CPU资源非常敏感。
无法处理浮动垃圾,可能出现Concurrent Mode Failure失败而导致另一次Full GC的产生。
会产生大量空间碎片。
G1收集器
G1是一款面向服务端应用的垃圾收集器。它在未来可以替换掉JDK1.5中发布的CMS收集器。
与其他GC收集器相比,G1具备如下特点:
并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短stop-the-world停顿的时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续运行。
分代收集:G1可以不需要其他收集器配合就能独立管理整个GC堆。
空间整合:G1从整体来看是基于标记-整理算法实现的收集器,从局部(两个Region之间)上来看是基于复制算法实现的,并且不会产生内存空间碎片,收集后能提供规整的可用内存。
可预测的停顿:不仅能降低停顿时间,还可以建立可预测的停顿时间模型。
使用G1收集器时,Java堆的内存布局就与其他收集器有很大区别,它将整个Java堆划分为多个大小相等的独立区域(region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,他们都是一部分Region(不需要连续)的集合。
G1收集器之所以能建立可预测的停顿时间的模型,是因为它可以有计划的避免整个Java堆中寄信全区域的垃圾收集。G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(这也就是Garbage-First名称的由来)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。
G1收集器的运作大致可划分为以下几个步骤:
初识标记(Initial Marking)
并发标记(Concurrent Marking)
最终标记(Final Marking)
筛选回收(Live Data Counting and Evacuation)
我们发现G1的前几个步骤的运作过程和CMS有许多相似之处。初始标记阶段仅仅 只是标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发执行时,能在正确可用的Region中创建新对象,这阶段需要停顿线程,但耗时很短。并发标记阶段是从GC Roots开始对堆中对象进行可达性分析,找出存活的时间,这阶段耗时较长,但可与用户程序并发执行。而最终标记阶段则是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这阶段需要停顿线程,但是可并行执行。最后在筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划,这个阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅提高收集效率。