经典垃圾收集器

Serial收集器:

        单线程工作的收集器,不是只能运行一个处理机,在进行垃圾回收工作的时候必须暂停其他所有工作线程-Stop The World,直到收集结束

垃圾回收机制的一个重要目标就是消除或者减少用户现场因为垃圾回收而造成的停顿【目前没有办法完全消除,只能不断缩短】

特点:简单而高效,与其他收集器的单线程相比,特别是内存资源受限的环境,内存消耗最小,单核处理器或处理器核心数目较少的环境下,没有线程交互的开销,专心做垃圾回收,回收效率高。Serial收集器对于运行在客户端模式下的虚拟机来说是一个很好的选择

 ParNew收集器:

        ParNew收集器实质上是Serial收集器的多线程并行版本,除了同时使用多条线程进行垃圾收集之外,其余的行为包括Serial收集器可用的所有控制参数(例如:-XX:SurvivorRatio、-XX:
PretenureSizeThreshold、-XX:HandlePromotionFailure等)、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一致,在实现上这两种收集器也共用了相当多的代码【还能与CMS收集器搭配使用】

特点:适合服务端模式下的HotSpot虚拟机

补充一下并发和并行:

并发:吃饭的时候突然来了个电话,不再吃饭而去打电话【在某段时间内执行多个线程-计算机要打印文件,但是文件还没准备好,那么计算机先去处理其他的事情】

并行:吃饭的时候来了个电话,边吃饭边打电话【在同一时间执行不同线程-计算机一边打印文件,一边下载资源】

Parallel Scavenge收集器(吞吐量优先收集器):

        Parallel Scavenge收集器也是一款新生代收集器,它同样是基于标记-复制算法实现的收集器,也是能够并行收集的多线程收集器

         特点:Parallel Scavenge收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput)。所谓吞吐量就是处理器用于运行用户代码的时间与处理器总消耗时间的比值

停顿时间越短就越适合需要与用户交互或需要保证服务响应质量的程序,良好的响应速度能提升用户体验;而高吞吐量则可以最高效率地利用处理器资源,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的分析任务 

吞吐量和停顿时间需要一个度的调节,为什么这么说呢?垃圾收集停顿时间缩短是以牺牲吞吐量和新生代空间为代价换取的:系统把新生代调得小一些,收集300MB新生代肯定比收集500MB快但这也直接导致垃圾收集发生得更频繁,原来10秒收集一次、每次停顿100毫秒,现在变成5秒收集一次、每次停顿70毫秒。停顿时间的确在下降,但吞吐量也降下来了

Serial Old收集器:

        Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记-整理算法。这个收集器的主要意义也是供客户端模式下的HotSpot虚拟机使用

Parallel Old收集器:

        Parallel Old是Parallel Scavenge收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现

CMS收集器:

        CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,CMS收集器是基于标记-清除算法实现的,整个过程分为四部:

        1)初始标记(CMS initial mark)

                需要stop the world,仅仅标记GCRoots能够直接关联的对象,速度很快
        2)并发标记(CMS concurrent mark)

                从GCRoots的直接关联对象开始遍历整个对象图的过程,耗时长,不需要停顿用户线程,可以与垃圾收集现线程并发执行
        3)重新标记(CMS remark)

                需要stop the world,修正并发标记期间因为用户程序继续运作导致标记发生变动的那部分对象,停顿时间比初始标记长,比并发标记短
        4)并发清除(CMS concurrent sweep)

                清楚删除掉标记的阶段判断的已经死亡的对象,不需要移动存活对象可以与用户线程并行

特点: 并发收集、低停顿。CMS收集器对处理器资源非常敏感。事实上,面向并发设计的程序都对处理器资源比较敏感。在并发阶段,它虽然不会导致用户线程停顿,但却会因为占用了一部分线程(或者说处理器的计算能力)而导致应用程序变慢,降低总吞吐量。可能导致用户程序的执行速度忽然大幅降低

I-CMS变种:

        在CMS的基础上,并发标记、清理的时候让收集器线程、用户线程交替运行,尽量减少垃圾收集线程的独占资源的时间,这样整个垃圾收集的过程会更长,但对用户程序的影响就会显得较少一些,直观感受是速度变慢的时间更多了,但速度下降幅度就没有那么明显【效果一般,已经被废弃】

浮动垃圾:在标记过程后产生的对象,无法在本次收集中收集只能等下一次收集的垃圾在CMS的并发标记和并发清理阶段,用户线程是还在继续运行的,程序在运行自然就还会伴随有新的垃圾对象不断产生,但这一部分垃圾对象是出现在标记过程结束以后,CMS无法在当次收集中处理掉它们,只好留待下一次垃圾收集时再清理掉

CMS在收集极端用户线程继续执行,因此会产生新的对象和新的垃圾。不能等老年代完全被填满再收集(需要留一定空间给用户使用),这“一部分空间”是可以设置的,但是设置太高,没有内存分配就会出现一次“并发失败”(Concurrent Mode Failure),这时候虚拟机将不得不启动后备预案:冻结用户线程的执行,临时启用Serial Old收集器来重新进行老年代的垃圾收集,但这样停顿时间就很长了;而设置太低,无法降低内存回收频率,不能获取更好的性能

Garbage First收集器:

        开创了收集器面向局部收集的设计思路和基于Region的内存布局形式被Oracle官方称为“全功能的垃圾收集器”(Fully-Featured Garbage Collector)G1是一款主要面向服务端应用的垃圾收集器

停顿时间模型:

        停顿时间模型的意思是能够支持指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间大概率不超过N毫秒这样的目标

在G1收集器出现之前的所有其他收集器,包括CMS在内,垃圾收集的目标范围要么是整个新生代(Minor GC),要么就是整个老年代(Major GC),再要么就是整个Java堆(Full GC)。而G1跳出了这个樊笼,它可以面向堆内存任何部分来组成回收集(Collection Set,一般简称CSet)进行回收,衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大,这就是G1收集器的Mixed GC模式。

G1堆内存布局:

        G1不再坚持固定大小以及固定数量的分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。收集器能够对扮演不同角色的Region采用不同的策略去处理,这样无论是新创建的对象还是已经存活了一段时间、熬过多次收集的旧对象都能获取很好的收集效果

Region的记忆集记忆了谁指向了自己,又记录了我指向谁,比原来的卡表实现起来更复杂,同时由于Region数量比传统收集器的分代数量明显要多得多,因此G1收集器要比其他的传统垃圾收集器有着更高的内存占用负担。根据经验,G1至少要耗费大约相当于Java堆容量10%至20%的额外内存来维持收集器工作 

当用户线程改变引用关系:G1通过原始快照的方法解决

当用户线程有新对象建立时:G1为每一个Region设
计了两个名为TAMS(Top at Mark Start)的指针,把Region中的一部分空间划分出来用于并发回收过程中的新对象分配,并发回收时新分配的对象地址都必须要在这两个指针位置以上。G1收集器默认在这个地址以上的对象是被隐式标记过的,即默认它们是存活的,不纳入回收范围

当碰上内存回收赶不上内存分配时,会采取stop the world,冻结用户线程

G1收集器的运作过程大致可划分为以下四个步骤:

·初始标记(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收集器除了并发标记外,其余阶段也是要完全暂停用户线程的,换言之,它并非纯粹地追求低延迟,官方给它设定的目标是在延迟可控的情况下获得尽可能高的吞吐量

【可以由用户指定停顿时间,设置不同的期望停顿时间,可使得G1在不同应用场景中取得关注吞吐量和关注延迟之间的最佳平衡 如果我们把停顿时间调得非常低,譬如设置为二十毫秒,很可能出现的结果就是由于停顿目标时间太短,导致每次选出来的回收集只占堆内存很小的一部分,收集器收集的速度逐渐跟不上分配器分配的速度,导致垃圾慢慢堆积。很可能一开始收集器还能从空闲的堆内存中获得一些喘息的时间,但应用运行时间一长就不行了,最终占满堆引发Full GC反而降低性能,简而言之就是优先考虑满足内存分配速率而不是将整个堆内存清理

优点:可以指定最大停顿时间、分Region的内存布局、按收益动态确定回收集。G1从整体来看是基于“标记-整理”算法实现的收集器,但从局部(两个Region之间)上看又是基于“标记-复制”算法实现,无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,垃圾收集完成之后能提供规整的可用内存。这种特性有利于程序长时间运行,在程序为大对象分配内存时不容易因无法找到连续内存空间而提前触发下一次收集

缺点:用户程序运行过程中,G1无论是为了垃圾收集产生的内存占用(Footprint)还是程序运行时的额外执行负载都很高

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值