JVM之垃圾收集器
垃圾回收算法:
标记-清除:先标记后统一清除
缺点:1.执行效率不稳定(表现在假设Java堆中存在大量需要被回收对象,此时标记-清除操作执行效率随着对象的数量增加而降低)2.产生大量碎片化空间,导致内存不连续,无法为大对象分配空间。
标记-复制:将内存分为两块,每次只使用一块,当这块内存用完了,就将还存活着的对象复制到另一块保留区域上,然后再把已使用过的内存空间一次性清理掉。
缺点:空间浪费
标记-整理:和“标记-清除”前期标记动作一样,不同的是标记-整理不是直接对可回收对象进行清除,而是将所有存活对象都往内存一端移动,然后清理掉边界以外的内存。
缺点:内存回收变复杂
垃圾回收器:
串行收集器:
Serial:单线程,收集时需暂停所有的应用线程,直到收集完成。优点:简单高效,无线程切换开支。缺点:stw停顿预期不稳定。
Serial Old:是Serial收集器的老年代版,在客户端模式下HotSpot虚拟机使用。在服务端模式下:1.可搭配Parallel Scavenge 使用。2.可作为CMS收集器的备选方案使用
并行收集器:
ParNew: 实质上是Serial的多线程版本,除此之外,并无太多创新之处。
Parallel Scavenge:是一个多线程的新生代收集器,与其他收集器关注点不一样,它的目标是达到一个到预期的吞吐量(吞吐量:运行用户代码时间与运行代码时间+垃圾收集时间的比值),也称为“吞吐量优先垃圾收集器”,同时Parallel Scavenge提供参数可动态控制吞吐量或stw时间,可自行配置若不熟练可直接使用默认配置。
Parallel Old:是Parallel Scavenge 的老年代版,支持多线程,基于“标记-整理”算法实现。PS+PO实现“吞吐量优先”收集器的搭配组合。
CMS:以一种获取“最短停顿时间”为目标的收集器,也称为“并发低停顿收集器”。致力于缩短停顿时间,给用户带来良好体验。主要基于“标记-清除”算法实现,收集过程分为四个步骤:
1.初始标记(CMS Initial mark):标记一下“GC Roots”能直接关联到的对象。
2.并发标记(CMS concurrent mark):开始从“GC Roots”的直接关联对象,遍历整个对象图的过程,耗时很长,但不需要停掉用户线程,可以与垃圾回收器并发运行。
3.重新标记(CMS remark):目的是为了纠正因与用户程序一起运作而产生标记变动那一部分对象的记录,停顿时间比“初始标记”长,比“并发标记”短。
4.并发清除(CMS concurrent sweep):清除删除掉标记阶段标记的已“死掉”的对象,由于不需要移动存活对象,因此此操作也是可与用户线程并发进行。
缺点:1.对CPU资源非常敏感。
2.无法处理“浮动垃圾”,可能导致Full GC产生。
3.由于使用“标记-清除”算法实现垃圾回收算法,会产生大量碎片化内存空间。
Garbage First(G1):堆仍然有新生代(eden、survivor)、老年代的划分,但是不再要求它们是内存连续的,还有一类特殊的Humongous区用来存放大对象(大对象定义:G1认为超过Region容量一半的对象)。每个区都由多个Region组成,G1之前的垃圾回收器的目标范围主要是要么整个新生代、要么整个老年代,要么是整个Java堆。而G1可以面向对内存任何部分组合成垃圾回收集,设计为将堆内存“化整为零”的设计思路,衡量标准不再是属于哪个分代,而是哪里存放垃圾最多,收益最大。基于Region内存布局的G1,是一款面向“服务端”应用的垃圾回收器,被Oracle官方誉为“全功能垃圾回收器”。JDK7替换掉了JDK5中的CMS,JDK9种替换掉了PS+PO组合。
G1收集器运作过程:
1.初始标记(Initial marking):标记一下“GC Roots”能直接关联到的对象,修改TAMS指针。
2.并发标记(concurrent marking):开始从“GC Roots”的直接关联对象,对堆中对象进行可达性分析,递归扫描整个堆中的对象图,找出可回收对象,且扫描完后重新处理SATB记录下的在并发时,引用变动的对象。
3.最终标记(final remarking):对用户线程做另一个短暂的暂停,用于处理并发阶段 结束后仍遗留下来的最后那少量的 SATB 记录。
4.筛选回收(Live data counting and evacuation):负责更新 Region 的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个 Region 构成回收集,然后把决定回收的那一部分 Region 的 存活对象复制到空的Region中,再清理掉整个旧Region的全部空间。
Shenandoah:Shenandoah作为第一款不由Oracle(包括一起的Sun)公司的虚拟机团队所领导开发的HotSpot垃圾收集器。只存在于OpenJDK当中的,最初由RedHat公司创建的,在2014年的时候贡献给了OpenJDK。与G1有很多类似之处,其中有相同的堆内存布局,收集过程设计思路也有许多相似之处。
Shenandoah相较于G1的改进之处:
1.支持并发整理算法。Shenandoah可与用户线程并发操作。
2.Shenandoah默认不使用分代收集。
3.Shenandoah摒弃了在G1中耗费大量内存维护的记忆集,改用“连接矩阵”的全局数据结构来记录跨Region的引用关系,降低了处理跨代指针时的记忆集的维护消耗,同时降低了伪共享问题的发生概率。
参考资料:周志明.著 《深入理解Java虚拟机》