经典垃圾收集器

四.经典垃圾收集器:

1.Serial收集器

	1.当它进行垃圾收集时,必须暂停其他所有工作进程,直到收集结束。是客户端模式下默认新生代收集器。在内存资源受限时,它的额外内存消耗最小。(标记复制)

2.ParNew收集器

  1. 实质上是Serial的多线程并行版本。在JDK7之前,只有它能与CMS配合工作。
  2. 在单核环境下或者说通过超线程技术实现的伪双核处理器环境下都不能百分百超越Serial收集器。随着被使用的处理器核心数量的增加,对于资源的利用还是很好的。(标记复制)

3.Paeallel Scabenge收集器

  1. (标记复制)CMS等收集器关注的是缩短用户线程的停顿时间,而PS收集器的目标是达到一个可控制的吞吐量。所以又叫做吞吐量优先收集器。
  2. 还有一个参数-XX:+UseAdaptiveSizePolicy,开启后会根据当前系统的运行情况收集性能监控信息,动态调整参数以提供最合适的停顿时间或最大的吞吐量。(自适应调节策略也是PS收集器区别于ParNew收集器的重要特性)

4.Serial Old收集器

  1. (标记整理)主要意义是供客户端模式下的虚拟机使用。服务端模式下,与JDK5版本以及之前与PS收集器搭配使用或作为CMS发生失败时的后备预案。

5.Parallel Old收集器

  1. (标记整理)JDK6才开始提供,出现之前,PS在老年代只能与Serial Old以外别无选择。所以在老年代内存空间很大而且硬件规格比较高级的运行环境中,这种组合的总吞吐量甚至不一定比ParNew加CMS的组合来得优秀。
  2. 直到Parallel Old收集器出现后,“吞吐量优先”收集器终于有了比较名副其实的搭配组合,在注重吞吐量或者处理器资源较为稀缺的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器这个组合。

6.CMS收集器

  1. (标记清除)关注服务的响应速度,希望系统停顿时间尽可能短。
  2. 分为4个阶段:初始标记(STW,仅仅只是标记一下GC Roots能直接关联的对象),并发标记(从GC Roots的直接关联对象开始遍历整个对象图,过程较长,但是不需要停顿用户线程)。重新标记(STW,为了修正并发标记期间,用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,比初始标记停顿的时间稍长一些),并发清除。
  3. CMS对处理器资源非常敏感,并发阶段,虽然不会导致用户线程停顿,但会因为占用了一部分线程导致系统变慢,降低总吞吐量。默认的回收线程数是(处理器核心+3)/4,核心不足4个时,对系统影响很大。
  4. 由于无法处理浮动垃圾(在并发标记和并发清理阶段,产生的垃圾无法在这次清除),有可能出现并发失败导致另一次STW的Full GC。
  5. 由于在垃圾收集阶段用户线程还需要持续运行,那就还需要预留足够内存空间提供给用户线程使用,因此CMS收集器不能像其他收集器那样等待到老年代几乎完全被填满了再进行收集,必须预留一部分空间供并发收集时的程序运作使用。-XX:CMSInitingOccupancyFraction可以设置CMS的触发百分比,但是设置太高,预留的内存无法满足分配新对象的需要,就会出现并发失败,冻结用户线程的执行,临时启用Serial Oldlai来收集,停顿很长。
  6. 由于会有大量空间碎片的产生,JDK9之前在FullGC的时候会整理内存,但必须移动存活对象,停顿时间又会变长。因此又提供了一个参数,在执行过若干次Full GC后,下次会先进行碎片整理。默认为0。
  7. CMS并不符合职责分离的设计原则,所以在规划JDK10时。HotSpot提出了"统一垃圾收集器接口",将内存回收的行为和实现分离,CMS以及其他都重构于这套接口。

7.G1收集器

  1. 开创了面向局部收集的设计思路和基于Region的内存布局。JDK9取代PS+ParallelOld组合,成为服务端模式下默认垃圾收集器。
  2. 它面向堆内存任意部分来组成回收集进行回收,衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最大,回收收益最大。G1开创的机遇Region的堆内存布局是关键,它把堆划分为多个大小相等的Region,每一个Region都可以根据需要扮演不同的角色。
  3. Region里有一类特殊的Humongous区域,专门用来存储大对象,G1认为只要超过了一个Region大小的一半就是大对象。而超过了整个Region的大对象,将会被存放在N个连续的Humongous Region之中(老年代)。
  4. G1去跟踪各个Region里面的垃圾堆积的价值大小,然后在后台维护一个优先级列表,每次根据用户设定的收集停顿时间,优先处理回收价值收益最大的Region。
  5. 每个Region都维护自己的记忆集,会录下别的Region指向自己的指针,并标记这些指针分别在哪些卡页的范围内,是一种哈希表,Key是别的Region的起始地址,Value是一个集合,储存的元素是卡表的索引号。(这是一种双向的卡表的结构,卡表是我指向谁,这种还记录了谁指向我),因此内存占用更大。
  6. G1为每一个Region设置了2个指针,把Region中的一部分空间划分出来用于并发回收过程中的新对象分配,新分配的对象地址必须要在这两个指针上,G1默认在这个地址的对象是存活的。与CMS并发失败导致Full GC相似,如果内存回收的速度赶不上内存分配的速度,G1也会Full GC导致STW。
  7. G1收集器的停顿预测模型是以衰减均值为理论基础来实现的,在垃圾收集过程中,会记录每个Region的回收耗时,每个Region记忆集里的脏卡数量等,衰减平均值是指会比普通的平均值更容易受到新数据的影响。
  8. 运作过程可分为4个步骤:1.初始标记(仅仅标记GC Roots能直接关联的对象,并且修改TAMS指针的值,让下一阶段用户线程并发运行时,能正确地在可用的Region中分配新对象,STW很短,且借用Minor GC时同步完成);2.并发标记(从GC Roots进行可达性分析,耗时较长,但可并发,当对象图扫描完成以后,还要重新处理SATB记录下引用变动的情况);3.最终标记:STW,用于处理并发结束后仍遗留下来的少量SATB记录;4.筛选回收:负责更新Region的统计数据,对各个Region回收价值排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region构成回收集,把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧Region的全部空间。涉及存活对象的移动,必须STW。
  9. 除了并发标记外,其余阶段都要STW,它并非追求低延迟,而是在延迟可控的情况下获得高的吞吐量。
  10. 相比CMS,与标记-清除算法不同,G1是基于标记-整理的收集器,但从局部(两个Region之间)又是基于标记-复制算法。这2种算法都意味着不会产生内存空间碎片。但内存占用和额外执行负载都比CMS要高。G1的卡表更为复杂,内存消耗占20%甚至以上。
  11. 在执行负载的角度上,CMS用写后屏障来更新维护卡表,G1则使用相同的写后屏障,但为了实现原始快照搜索(SATB),还需要使用写前屏障来跟踪并发时的指针变化情况。相比起增量更新算法,原始快照能够减少并发标记和重新标记阶段的消耗,避免CMS在最终标记阶段停顿时间过长,但是会增加跟踪引用变化带来的额外负担。 由于G1的写屏障要比CMS消耗更多的运算资源,CMS的写屏障实现是直接的同步操作,G1就不得不将其实现为类似消息队列的结构,把写前屏障和写后屏障的事情都放在队列里,再异步处理。

8.Shenandoah收集器

  1. 在堆内存布局上和G1相似,在初始标记,并发标记等阶段都高度一致。
    不同之处在于:1.支持并发的整理算法,G1的回收阶段可以多线程并行,但却不能与用户线程并发。
    2.默认不使用分代收集。3.摒弃了G1中耗费大量内存和计算资源去维护的记忆集,该用连接矩阵的全局数据结构来记录跨Region的引用关系,降低了维护消耗,也降低了伪共享的发生概率(相当于二维表格实现)
  2. 工作过程:1.初始标记(与G1一样,首先标记GC Roots直接关联的对象,STW,停顿时间只与GC Roots有关)
    2.并发标记(与G1一样,遍历对象图,标出全部可达的对象,并发,当对象图扫描完成以后,还要重新处理SATB记录下引用变动的情况)
    3.最终标记(与G1一样,处理剩余的SATB扫描,并在这个阶段统计出回收价值最高的Region,构成回收集,很小段STW)
    4.并发清理(用于清理整个区域内一个存活对象都没有找到的Region)
    *5.并发回收(把回收集里面的存活对象复制到一份未被使用的Region之中,并发的困难在于:在移动对象的同时,用户线程可能对移动的对象进行读写访问),该收集器通过读屏障和称为"Brooks Pointers"的转发指针来解决。
    6.初始引用更新(并发回收复制对象结束后,还需要引用更新:把堆中所有指向旧对象的引用修正到复制后的新地址),这个阶段只是为了建立一个线程集合点,确保所有所有线程都已完成对象移动任务,短暂的STW。
    7.并发引用更新(与用户线程并发,与并发标记不同,它不需要沿着对象图来搜索,只需要按照内存物理地址,线性地搜索出引用类型,把旧值改成新值即可)
    8.最终引用更新(解决了堆中的引用更新后,还要修正GC Roots中的引用,最后1次STW)
    9.并发清理(Region中再无存活对象,最后调用一次并发清理来回收这些Region)
  3. 并发整理:通常是在被移动对象原有的内存设置保护陷阱,一旦访问到该内存就会产生自陷中断,进入预设的异常处理器,再把访问转发到复制后的新对象上。PS:如果没有操作系统的直接支持,会导致用户态频繁切换到核心态,代价很大,不能频繁使用
    Brooks Pointer:在原有对象布局结构最前面统一增加一个新引用字段,在正常时该引用指向对象自己,与句柄定位相似。这样只要旧对象的内存仍然存在,所有通过旧引用地址访问的代码仍然可用,都会被自动转发到新对象上继续工作。
    Brooks指针会出现多线程竞争问题,如果只是并发读取,那无论读到旧对象还是新对象,结果都是一样的。但如果是并发写入,就必须保证写操作只能发生在新复制的对象上。所以对转发指针的操作必须采取同步措施,让收集器线程或用户线程对转发指针的访问只有一个能成功,实际上是通过CAS操作(比较并交换)来保证正确性。
    对于对象的读取,写入,对象的比较,哈希值计算,用对象加锁等都属于对象访问的范畴,要覆盖全部对象访问操作,必须设置读,写屏障来拦截。写屏障用于维护卡表或实现并发标记。
    该虚拟机用到了写屏障,除此之外,为了实现Brooks指针,虚拟机在读,写屏障中都加入了额外的转发处理,读屏障数量比写屏障多得多,所以不允许任何的重要级操作,为了处理数量庞大的读屏障带来的性能开销,JDK13中将内存屏障模型改进为引用访问屏障(只拦截对象中引用类型的读写操作,而不管原生数据类型等其他非引用字段的读写)

9.ZGC收集器

  1. 是一款基于Region内存布局,(暂时)不设分代的,使用了读屏障,染色指针和内存多重映射等技术来实现并发的标记整理,以低延迟为首要目标的一款垃圾收集器。
  2. Region具有动态性,分为小型:2MB,放置小于256KB的小对象;中型:32MB,放置大于等于256KB但小于4MB的对象;大型:容量可以动态变化,但必须为2MB的整数倍,每个大型Region只会存放一个大对象。最低至4MB,不会被重分配,因为复制一个大对象的代价非常高昂。
  3. 标记实现方案:1.把标记直接记录在对象头上(Serial); 2.把标记记录在与对象相互独立的数据结构上(G1,Shenandoah使用了一种堆内存1/64大小,称为BitMap的结构);3.ZGC则使用染色指针把标记信息记在引用对象的指针上。 染色指针将64位系统的剩余46位的高4位提取出来储存4个标志信息(是否被移动,是否只能通过finalize()访问,Marked0,Marked1),也压缩了地址空间,管理不可以超过4TB(2的42次幂)。
  4. 染色指针3大优势:1.一旦某个Region的存活对象被移走之后,这个Region立即就能被释放和重用,而不必等整个堆指向Region的引用都被修正后才能清理。——>理论上只要还有一个空闲Region,就能完成收集。而Shenandoah需要等到引用更新结束后才能释放回收集里的Region。
    2.设置内存屏障,尤其是写屏障通常是为了记录对象引用的变动情况,但如果把这些信息直接维护在指针中,就可以省去一些专门的记录操作。ZGC到现在并未使用任何写屏障(一部分是染色指针的原因,一部分是ZGC现在还不支持分代收集,天然就没有跨代引用的原因)
  5. 为了顺利应用染色指针,处理器会使用分页管理机制把线性地址空间和物理地址空间分别划分为大小相同的块,通过在这2页之间建立映射表,完成线性地址到物理地址的转换。ZGC使用了多重映射,将多个不同的虚拟地址映射到同一个物理地址上,是多对一。
  6. 运行过程:1.并发标记:与其他虚拟机一样,是做可达性分析的阶段,前后也要经历初始标记和最终标记,但标记是在指针上而不是在对象上进行的,会更新染色指针中的Marked0,Marked1标志位。
    2.并发预备重分配:根据特定的查询条件统计出本次要清理哪些Region,将这些Region组成重分配集,与G1收益优先不同,ZGC每次回收都会扫描所有的Region,用范围更大的扫描成本省去记忆集的维护成本。
    3.并发重分配:把重分配集中的存活对象复制到新的Region上,并为每个Region维护一个转发表,记录从旧对象到新对象的转向关系。得益于染色指针的支持,仅从引用上就可以知道对象是否在重分配集中,如果用户线程此时并发访问了位于重分配集里的对象,这次访问会被内存屏障所截获,然后立即根据Region上的转发表记录将访问转发到新复制的对象上,并同时修正更新引用的值,使它直接指向新对象。好处:只有第一次访问旧对象会陷入转发,只慢一次,Shenandoah的Brooks转发指针,每次都慢。
    4.并发重映射:修正整个堆中指向重分配集中旧对象的所有引用,但是并不迫切去完成,即使是旧引用,也是可以自愈的,该阶段主要目的是为了不变慢,清理结束后可以释放转发表。ZGC把它合并到了下一次的并发标记去完成,因为它们都是要遍历所有对象的。
  7. 没有记忆集和卡表导致它能承受的对象分配速率不会太高,由于对象的分配的速率很高,这些新对象很难进入档次收集的标记范围,这就产生了很多的浮动垃圾,如果回收到的内存空间持续小于浮动垃圾占用的空间,可用空间就越来越小了。

10.epsilon收集器

  1. Epsilon收集器没有垃圾收集行为,用于短时间,小规模的应用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值