java中的垃圾收集器是什么

发布时间:2021-09-04 11:55 来源:亿速云 阅读:0 作者:chen 栏目: 开发技术

本篇内容介绍了“java中的垃圾收集器是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

目录
  • 1.经典垃圾收集器

    • 1.1 Serial收集器

    • 1.2 ParNew收集器

    • 1.3 Parallel Scavenge 收集器

    • 1.4 Serial Old 收集器

    • 1.5 Parallel Old 收集器

    • 1.6 CMS 收集器

    • 1.7 Garbage First 收集器

  • 2低延迟垃圾收集器

    • 2.1 Shenandoah收集器

    • 2.2 ZGC收集器

  • 总结

    1.经典垃圾收集器

    1.1 Serial收集器

    这个收集器是一个单线程工作的收集器,但它的单线程的意义并不仅仅是说明他只会使用一个处理器或一条收集线程去完成垃圾收集工作,更重要对的是强调在它进行垃圾收集时,必须暂停其他所有工作线程,直到它收集结束。

    目前已经老无可用,但有着优于其他收集器的地方:简单而高效

    1.2 ParNew收集器

    ParNew收集器实质上是Serial收集器的多线程并行版本。因为它是除了Serial收集器之外,目前唯一可以与CMS收集器配合工作的收集器,所以在JDK7之前的遗留系统中被作为首选的新生代收集器

    CMS收集器是HotSpot虚拟机中第一款真正意义上支持并发的垃圾收集器,首次实现了让垃圾收集线程与用户线程同时工作。但是当选用CMS作为老年代收集器时,新生代收集器只能选择使用Serial收集器或者ParNew收集器

    随着垃圾收集器技术的不断改进,G1收集器带着CMS继承者和代替者的光环登场。G1收集器是一个面向全堆的收集器,不需要其他新生代收集器的配合工作

    1.3 Parallel Scavenge 收集器

    Parallel Scavenge收集器也是一款新生代收集器,同样是基于标记-复制算法实现的收集器,也可以并行收集的多线程收集器。它的特点是它的关注点与其他收集器不同。CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量。

    $$

    吞吐量=\frac{运行用户代码时间}{运行用户代码时间+运行垃圾收集时间}

    $$

    提供了两个参数用于精确控制吞吐量:

    -XX:MaxGCPauseMillis 参数控制最大垃圾搜集停顿时间,允许的值是一个大于0的毫秒数。收集器将尽力保证内存回收花费的时间不超过用户的设定值。但是设定过分小的值并不能起到加快回收花费的速度的作用。

    -XX:GCTimeRatio 参数直接设置吞吐量大小,允许的值是一个大于0小于100的整数。也就是垃圾收集时间占总时间的比率。相当于吞吐量的倒数。

    Parallel Scavenge 收集器还有一个参数:-XX:+UseAdaptiveSizePolicy 这是一个开关参数,当这个参数被激活以后,就不需要人工指定新生代的大小,Eden与Survivor区的比例等等。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数。

    1.4 Serial Old 收集器

    Serial Old 是 Serial收集器的老年代版本,同样是一个单线程收集器,使用标记-整理算法。可能有两种用途:1. 在JDK5以及之前的版本中与Parallel Scavenge收集器搭配使用 2. 作为CMS收集器发生失败时的后备预案。

    1.5 Parallel Old 收集器

    Parallel Old 是 Parallel Scavenge收集器的老年代版本,支持多线程并发收集,基于标记-整理算法实现,从JDK6版本开始提供。在注重吞吐量或者处理器资源较为稀缺的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器这个组合。

    1.6 CMS 收集器

    CMS收集器是一种以获取最短回收停顿时间为目标的收集器,基于标记-清除算法实现。整个运作过程分为4步:

    CMS收集器存在三个缺点:

    1.CMS收集器对处理器资源非常敏感,默认启动的回收线程数为(处理器核心数量+3)/ 4。在并发阶段会因为占用了一部分线程而导致应用程序变慢,降低总吞吐量。

    为了缓解这种情况虚拟机提供了“增量式并发收集器”(Incremental Concurrent Mark Sweep/i-CMS)作用是在并发标记、清理的时候让收集器线程、用户线程交替运行,尽量减少垃圾收集器线程的独占资源的时间,这样整个垃圾收集的过程会更长,但是对用户程序的影响就会显得较少一些,直观感受是速度变慢的时间更多了,但速度下降幅度就没有那么明显。效果一般从jdk7开始被声明为deprecated ,从JDK9发布后被完全废弃

    2.由于CMS收集器无法处理“浮动垃圾”(Floating Garbage),有可能出现"Concurrent Mode Failure" 失败进而导致另一完全"Stop The World"的Full GC的产生。

    可以适当调高参数-XX:CMSInitiatingOccu-pancyFraction的值来提高CMS的触发百分比,降低内存回收频率,获得更好的性能。如果设置的太高将会很容易导致大量的并发失败产生,性能反而降低

    3.由于基于标记-清除算法,可能在收集结束时会有大量的空间碎片产生

    通过调节:-XX:+UseCMSCompactAtFullCollection开关参数,默认是开启的,从jdk9开始废弃

    *** -XX:CMSFullGCsBeforeCompaction 默认值是0,表示每次进入Full GC时都进行碎片整理***

    1.7 Garbage First 收集器

    Garbage First 收集器,简称 G1收集器,开创了收集器面向局部收集的设计思路和基于Region的内存布局形式。是一款主要面向服务端应用的垃圾收集器。可以面向堆内存的任何部分来组成回收集,衡量的标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大。G1开创的基于Region的堆内存布局是它能够实现这个目标的关键,G1不再坚持固定大小以及固定数量的分代区域划分,而是把连续的java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间或者老年代空间。

    Region中还有一类特殊的Humongous区域,专门用来存储大对象。G1认为只要大小超过了Region容量一半的对象就可以判定为大对象。每个Region的大小可以通过参数-XX:G1HeapRegionSize设定,取值范围为1MB~32MB。

    G1收集器之所以可以建立可预测的停顿时间模型,是因为它将Region作为单次回收的最小单元,即每次收集到的内存空间都是Region大小的整数倍,这样可以有计划地避免在整个JAVA堆中进行全区域的垃圾收集。更具体的思路是让G1收集器区跟踪各个Region里面的垃圾堆积的价值大小,价值即回收所获得的空间大小以及回收所需要的时间的经验值,然后在后台 维护一个优先级列表,每次根据用户设定允许的收集停顿时间(-XX:MaxGCPauseMillis)优先处理回收价值收益最大的那些Region。

    G1的记忆集在存储结构的本质上是一种哈希表,Key是别的Region的起始地址,Value是一个集合,里面存储的元素是卡表的索引号。G1收集器通过原始快照(SATB)算法实现了保证其不能打破原本的对象图结构的目的。

    G1收集器运作过程大致分为四个步骤:

    2低延迟垃圾收集器

    2.1 Shenandoah收集器

    Shenandoah收集器是一款只有OpenJDK才会包含的。与G1收集器相比,它们两者有着相似的堆内存布局,在初始标记、并发标记等许多阶段的处理思路上都高度一致。但是在管理内存堆方面,与G1收集器至少有三个方面的明显的不同之处:

    1.支持并发的整理算法:G1的回收阶段是可以多线程并行的,但不能与用户线程并发。Shenandoah后面会讲到。

    2.Shenandoah收集器默认不使用分代收集。

    3.Shenandoah摒弃了在G1中耗费大量内存和计算资源去维护的记忆集,改名为“连接矩阵”(Connection Matrix)的全局数据结构来记录跨Region的引用关系。降低了处理跨代指针的记忆集维护消耗,也降低了伪共享问题发生的概率

    Shenandoah收集器大致工作流程可以分为9个阶段:

    Brooks Points:Brooks是一个人的名字,它提出使用了转发指针(Forwarding Pointer)的技术来实现对象移动与用户程序并发的一种解决方案。不需要用到内存保护陷阱,而是在原有对象布局结构的最前面统一增加一个新的引用字段,在正常不处于并发移动的情况下,该引用指向对象自己。实际上Shenandoah收集器是通过比较并交换(Compare And Swap, CAS)操作来保证并发时对象的访问正确性的。

    JDK13中Shenandoah的内存屏障模型改进为基于引用访问屏障(Load Reference Barrier)的实现,所谓“引用访问屏障”是指内存屏障只拦截对象中数据类型为引用类型的读写操作,而不去管原生数据类型等其他非引用字段的读写。这能省去大量对原生类型、对象比较、对象加锁等场景中设置内存屏障所带来的消耗。

    2.2 ZGC收集器

    ZGC收集器是一款基于Region内存布局的,暂时不设分代的,使用了读屏障、染色指针和内存多重映射等技术来实现可并发的标记-整理算法的,以低延迟为首要目标的一款垃圾收集器。

    ZGC的Region具有动态性-动态创建和销毁,以及动态的区域容量大小。

    染色指针(Colored Pointer):一种直接将少量额外的信息存储在指针上的技术。尽管在linux下64位指针的高18位不能用来寻址,但是剩余的46位所能支持的64TB内存仍然能够充分满足需要。鉴于此,将其高4位提取出来存储四个标记信息。通过这些标志位,虚拟机可以直接从指针中看到其引用对象的三色标记状态、是否进入了重分配集、是否只能通过finalize( )方法才能被访问到。也使得ZGC能够管理的内存不可以超过4TB。使用染色指针的三大优势:

    1.可以使得一旦某个Region的存活对象被移走之后,这个Region立即就能被释放和重用掉,不必等待整个堆中所有指向该Region的引用都被修正后才能清理。

    2.可以大幅度减少在垃圾收集过程中的内存屏障的使用数量。到目前为止,ZGC都未使用写屏障,只使用了读屏障。

    3.可以作为一种可扩展的存储结构用来记录更多与对象标记、重定位过程相关的数据,以便日后进一步提高性能。

    Linux/x86-64平台上的ZGC使用了多重映射将多个不同的虚拟内存地址映射到同一个物理内存地址上,意味着ZGC在虚拟内存中看到的地址空间要比实际的堆内存容量来得更大。把染色指针中的标志位看作是地址的分段符,只要将这些不同的地址段都映射到同一个物理内存空间,经过多重映射转换后,就可以使用染色指针正常进行寻址了。

    ZGC的运作过程(省略部分与之前介绍的G1和Shenandoah相同的小阶段部分):

    免责声明:本站发布的内容(图片、视频和文字)以原创、来自互联网转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系QQ:712375056 进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。