介绍一下垃圾回收器(不分顺序)
Serial:新生代垃圾回收器,单线程,采用的是复制算法,这个垃圾回收器在工作的时候,用户线程是不可以能工作的,这个用户线程停顿的时间,就称为stop-the-world,简称STW
Parallel Scavenge:新生代垃圾回收器,多线程,复制算法,会产生STW(JDK8默认的垃圾回收器组合是parallel Scavenge和parallel Old)
ParNew:新生代垃圾回收器,多线程,采用复制算法,会产生CMS,这个和parallel scavenge类似,唯一不同的是ParNew可以和CMS一起使用。
Serial old:老年代垃圾回收器,单线程,采用标记-整理的算法,它算是Serial的老年代版本
Parallel old:老年代垃圾回收器,多线程,采用标记-整理的算法,paralle scavenge的老年代版本
CMS:老年代垃圾回收器,并发多线程,采用标记-清除算法,是一种以获取最短回收时间为目标的垃圾回收器。CMS可谓划时代的垃圾回收器,它实现了用户线程和GC线程同时工作,但是由于当时算法不够完善,后续又出了其他更好的垃圾回收器,渐渐不再被使用。Jdk14移除了CMS垃圾回收器,属于被后浪拍死在沙滩上的前浪。
CMS处理垃圾的过程比较复杂,分为四个步骤
- 初始标记:标记一下GC-root直接关联到的对象,会产生STW,时间非常短
- 并发标记:用户线程并发执行,GC线程线程顺着引用链继续向下标记,时间较长,但是不会产生STW
- 重新标记:并发标记可能会产生两种问题1、用户线程进行中,又出现其他不要的垃圾2、被标记的有被使用了,重新标记的时候,会对这两种情况作出修正,执行时间相对并发标记较短,会产生STW
- 并发清理:GC开始回收标记的对象,用户线程正常进行
G1:G1垃圾回收器是一款非常厉害的垃圾回收器,jkd1.7正式发布,Jdk9把G1作为默认的垃圾回收器。
相比较于其他垃圾回收器,G1具备以下几个特点:
并发与并行:多线程执行垃圾回收,并且可以和在回收时与用户线程一起运行。
分代收集:在概念上G1也是分代收集器,但是物理逻辑上,新生代和老年代不再物理隔离,G1把内存分为多个大小相同的Region,默认是2048个,可以通过-XX:G1HeapRegionSize= N 2048设置
空间整合:和CMS的标记-清理不同,G1从整体来说是基于标记-整理的算法,从局部(两个Region)来看是基于复制算法实现的,这两种算法意味着G1不会产生内存空间碎片。
可预测的停顿:G1除了追求最短停顿时间以外,还建立了可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间段进行垃圾回收。
G1建立可预测的停顿时间模型,是因为G1跟踪各个Region里面的垃圾回收价值,在后台维护了一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region,这种方式可以有计划的避免在整个java堆中进行全区域的垃圾回收,大大提高了垃圾回收效率。
G1缺点:一个对象分配在某个Region,它不可能只跟这个Region里面的对象有引用关系,所以用可达性分析法判断对象是否存活时,可能会扫描整个堆才行。
解决方法:每个Region都有一个Remembered Set,虚拟机发现程序在对Reference类型进行写操作时,会产生一个Write barrier暂时中断写操作,检查Reference引用的对象是否处于不同的Region中,并保存相关信息在Remembered Set中。当G1工作时,根据Remembered Set里面的信息可以避免扫描整个堆。
G1工作步骤:
- 初始标记:标记一下GC Roots能直接关联到的对象
- 并发标记:根据引用链继续查找,时间较长
- 最终标记:修正在并发标记期间因用户线程运行导致的一些有改动的对象
- 筛选回收:首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。