Description
java中的七大GC收集器和四大GC算法
栏目:行业资讯 发布时间:2024-07-16
 1、serial 串行垃圾收集器,采用单线程收集垃圾  2、parallel 并行垃圾收集器,采用多线程收集垃圾  3、CMS(concurrentMarkSweep)并发标记收集 垃圾收集器,串行和并行同在,是前两种垃圾收集器的优化,较短时间进行STW(stop the world

  1、serial 串行垃圾收集器,采用单线程收集垃圾

  2、parallel 并行垃圾收集器,采用多线程收集垃圾

  3、CMS(concurrentMarkSweep)并发标记收集 垃圾收集器,串行和并行同在,是前两种垃圾收集器的优化,较短时间进行STW(stop the world),保证较快的响应速度。

  4、G1 新一代垃圾收集器,采用的region分区

  在这里插入图片描述

  在这里插入图片描述

  java8中默认使用的是ParallelGC

  年轻代GC

  1、UserSerialGC:串行垃圾收集器

  2、UserParallelGC:并行垃圾收集器

  3、UseParNewGC:年轻代的并行垃圾回收器

  新生代中采用的垃圾收集算法 基本都是 标记复制算法/复制拷贝

  老年代GC

  1、UserSerialOldGC:串行老年代垃圾收集器(已经被移除)

  2、UseParallelOldGC:老年代的并行垃圾回收器

  3、UseConcMarkSweepGC:(CMS)并发标记清除

  老年代中采用的来及收集算法 基本都是 标记清除,标记清除压缩

  youngGen 和 oldGen 使用的GC

  UseG1GC:G1垃圾收集器

  下面两个图很重要

  注意:下面图中指的是可以这样搭配,但是jvm中会有默认搭配机制

  在这里插入图片描述

  在这里插入图片描述

  一个单线程的收集器,在进行垃圾收集时候,必须暂停其他所有的工作线程(STW)直到它收集结束。

  新生代老年代都是单线程的垃圾回收

  STW: Stop The World

  串行收集器是最古老,最稳定以及效率高的收集器,只使用一个线程去回收但其在进行垃圾收集过程中可能会产生较长的停顿(Stop-The-World”状态)。虽然在收集垃圾过程中需要暂停所有其他的工作线程,但是它简单高效,对于限定单个CPU环境来说,没有线程交互的开销可以获得最高的单线程垃圾收集效率,因此Serial垃圾收集器依然是java虚拟机运行在Client模式下默认的新生代垃圾收集器。

  在这里插入图片描述

  如果让jvm使用Serial垃圾收集器

  -XX:+UseSerialGC

  实例:

  jvm配置参数

  -XX:+UseSerialGC -XX:+PrintGCDetails -XX:MaxHeapSize=5m -XX:InitialHeapSize=5m

  paraNew是在新生代中的并行多线程垃圾收集器,老年代采用单线程垃圾收集器。

  在这里插入图片描述

  ParNew(Young区)+ Serial Old的收集器组合,新生代使用复制算法,老年代采用标记-整理算法

  jvm参数配置

  -XX:+UseParNewGC -XX:+PrintGCDetails -XX:MaxHeapSize=5m -XX:InitialHeapSize=5m

  新生代和老年代都采用多线程的垃圾收集器

  在这里插入图片描述

  jvm参数配置

  -XX:+UseParallelGC -XX:+PrintGCDetails -XX:MaxHeapSize=5m -XX:InitialHeapSize=5m

  ParallelOld收集器是老年代采用的垃圾收集器,使用的算法是标记清除, 与之对应的新生代垃圾收集器ParallelScavenge

  上文介绍过

  即使我配置-XX:UseParallelOldGC,新生代默认也会配置成ParallelScavenge 注意这是默认的。新生代配置ParallelScavenge,老年代还是配置成这个

  CMS收集器(Concurrent Mark Sweep:并发标记清除)是一种以获取最短回收停顿时间为目标的收集器。

  适合应用在互联网站或者B/S系统的服务器上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短。

  CMS非常适合地内存大、CPU核数多的服务器端应用,也是G1出现之前大型应用的首选收集器。

  在这里插入图片描述

  注意

  新生代使用ParNew收集器,老年代会使用收集器SerialOldGC

  使用jvm参数配置

  -XX:+UseConcMarkSweepGC 新生代会自动使用ParNew

  开启该参数后,使用ParNew(Young区用)+ CMS(Old区用)+ Serial Old的收集器组合,Serial Old将作为CMS出错的后备收集器。

  4步过程:

  1、初始标记(CMS initial mark) - 只是标记一下GC Roots能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。

  2、并发标记(CMS concurrent mark)和用户线程一起 - 进行GC Roots跟踪的过程,和用户线程一起工作,不需要暂停工作线程。主要标记过程,标记全部对象。

  3、重新标记(CMS remark)- 为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍然需要暂停所有的工作线程。由于并发标记时,用户线程依然运行,因此在正式清理前,再做修正。

  4、并发清除(CMS concurrent sweep) - 清除GCRoots不可达对象,和用户线程一起工作,不需要暂停工作线程。基于标记结果,直接清理对象,由于耗时最长的并发标记和并发清除过程中,垃圾收集线程可以和用户现在一起并发工作,所以总体上来看CMS 收集器的内存回收和用户线程是一起并发地执行。

  优点:并发收集低停顿,响应速度快。

  缺点:并发执行,对CPU资源压力大,采用的标记清除算法会导致大量碎片。

  jvm参数配置

  -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:MaxHeapSize=5m -XX:InitialHeapSize=5m

  后面讲

  单线程,标记整理算法,不再赘述

  组合的选择

  单CPU或者小内存,单机程序

  -XX:+UseSerialGC

  多CPU,需要最大的吞吐量,如后台计算型应用(java8默认)

  -XX:+UseParallelGC(这两个相互激活)

  -XX:+UseParallelOldGC

  多CPU,追求低停顿时间,需要快速响应如互联网应用

  -XX:+UseConcMarkSweepGC

  -XX:+ParNewGC

  G1 (Garbage-First)收集器,是一款面向服务端应用的收集器

  特点:

  G1能充分利用多CPU、多核环境硬件优势,尽量缩短STW。

  G1整体上采用标记-整理算法,局部是通过复制算法,不会产生内存碎片。

  宏观上看G1之中不再区分年轻代和老年代。把内存划分成多个独立的子区域(Region),可以近似理解为一个围棋的棋盘。

  G1收集器里面讲整个的内存区都混合在一起了,但其本身依然在小范围内要进行年轻代和老年代的区分,保留了新生代和老年代,但它们不再是物理隔离的,而是一部分Region的集合且不需要Region是连续的,也就是说依然会采用不同的GC方式来处理不同的区域。

  G1虽然也是分代收集器,但整个内存分区不存在物理上的年轻代与老年代的区别,也不需要完全独立的survivor(to space)堆做复制准备。G1只有逻辑上的分代概念,或者说每个分区都可能随G1的运行在不同代之间前后切换。

  目的

  G1收集器的设计目标是取代CMS收集器,它同CMS相比,在以下方面表现的更出色:

  G1是一个有整理内存过程的垃圾收集器,不会产生很多内存碎片。

  G1的Stop The World(STW)更可控,G1在停顿时间上添加了预测机制,用户可以指定期望停顿时间。

  CMS垃圾收集器虽然减少了暂停应用程序的运行时间,但是它还是存在着内存碎片问题。于是,为了去除内存碎片问题,同时又保留CMS垃圾收集器低暂停时间的优点,JAVA7发布了一个新的垃圾收集器-G1垃圾收集器。

  G1是在2012年才在jdk1.7u4中可用。oracle官方计划在JDK9中将G1变成默认的垃圾收集器以替代CMS。它是一款面向服务端应用的收集器,主要应用在多CPU和大内存服务器环境下,极大的减少垃圾收集的停顿时间,全面提升服务器的性能,逐步替换java8以前的CMS收集器。

  主要改变是Eden,Survivor和Tenured等内存区域不再是连续的了,而是变成了一个个大小一样的region ,每个region从1M到32M不等。一个region有可能属于Eden,Survivor或者Tenured内存区域。

  在这里插入图片描述

  回收步骤

  G1收集器下的Young GC

  针对Eden区进行收集,Eden区耗尽后会被触发,主要是小区域收集+形成连续的内存块,避免内存碎片

  Eden区的数据移动到Survivor区,假如出现Survivor区空间不够,Eden区数据会部会晋升到Old区。

  Survivor区的数据移动到新的Survivor区,部会数据晋升到Old区。

  最后Eden区收拾干净了,GC结束,用户的应用程序继续执行。

  在这里插入图片描述

  4步过程:

  初始标记:只标记GC Roots能直接关联到的对象

  并发标记:进行GC Roots Tracing的过程

  最终标记:修正并发标记期间,因程序运行导致标记发生变化的那一部分对象

  筛选回收:根据时间来进行价值最大化的回收

  在这里插入图片描述

  -XX:+UseG1GC

  -XX:G1HeapRegionSize=n:设置的G1区域的大小。值是2的幂,范围是1MB到32MB。目标是根据最小的Java堆大小划分出约2048个区域。

  -XX:MaxGCPauseMillis=n:最大GC停顿时间,这是个软目标,JVM将尽可能(但不保证)停顿小于这个时间。

  -XX:InitiatingHeapOccupancyPercent=n:堆占用了多少的时候就触发GC,默认为45。

  -XX:ConcGCThreads=n:并发GC使用的线程数。

  -XX:G1ReservePercent=n:设置作为空闲空间的预留内存百分比,以降低目标空间溢出的风险,默认值是10%。

  开发人员仅仅需要声明以下参数即可:

  三步归纳:开始G1+设置最大内存+设置最大停顿时间

  -XX:+UseG1GC

  -Xmx32g

  -XX:MaxGCPauseMillis=100

  -XX:MaxGCPauseMillis=n:最大GC停顿时间单位毫秒,这是个软目标,JVM将尽可能(但不保证)停顿小于这个时间

  G1和CMS比较

  G1不会产生内碎片

  是可以精准控制停顿。该收集器是把整个堆(新生代、老年代)划分成多个固定大小的区域,每次根据允许停顿的时间去收集垃圾最多的区域。

  java -server jvm的各种参数 -jar jar/war包名