JVM的7种垃圾回收器(小结)

垃圾回收算法和垃圾回收器

对于JVM的垃圾回收算法有复制算法、标记清除、标记整理。

用阳哥的话就是:这些算法只是天上飞的理念,是一种方法论,但是真正的垃圾回收还需要有落地实现,所以垃圾回收器应运而生。

JVM回收的区域包括方法区和堆,jvm对于不同区域不同的特点采用分代收集算法,比如因为所有的对象都是在Eden区进行分配,并且大部分对象的存活时间都不长,都是“朝生夕死”的,每次新生代存活的对象都不多,所以新采取复制算法;而jvm默认是新生代的对象熬过15次GC才能进入老年代,所以老年代的对象都是生命周期比较长的,采用标记清除或者标记整理算法。

那么对于这些算法的实现都有什么呢?

新生代:serial、ParNew、Parallel
老年代:Serial Old、Parallel Old、CMS
全堆:G1

并且他们的搭配组合如下:

垃圾回收器

jvm的垃圾回收器大体上的分类主要包括四种:串行、并行、并发(CMS)和G1。

串行垃圾回收器(Serial):它为单线程环境设计并且只使用一个线程进行垃圾回收,会暂停所有的用户线程。所以不适合服务器环境。
并行垃圾回收器(Parallel):多个垃圾回收线程并行工作,此时用户线程是暂停的,适用于科学计算/大数据处理等弱交互场景。
并发垃圾回收器(CMS):用户线程和垃圾收集线程同时执行(不一定是并行,可能交替执行),不需要停顿用户线程。互联网公司多用它,适用于对响应时间有要求的场景。
G1垃圾回收器:G1垃圾回收器将堆内存分割成不同的区域然后并发的对其进行垃圾回收。

默认的垃圾回收器

平时我们没有配置什么jvm参数,程序也能正常执行,那么JVM默认的垃圾回收器是什么呢?

那么如何查看默认的回收器呢?有很多方式,这里简单列举几种:

1.命令行方式:

java -XX:+PrintCommandLineFlags -version

可以看到jdk8默认的是使用的Parallel并行回收器。

2、jvm参数设置

在JVM运行之前加入参数同样可以查看,其实这两种方式是差不多的

3.jps+jinfo

先使用jps查看java进程号,在使用jinfo查看该进程的配置

Serial收集器

Serial是一个单线程收集器,在进行垃圾收集的时候必须停下所有的工作(Stop The World) 。

串行收集器是最古老,最稳定以及效率高的收集器,只使用一个线程去回收但其在进行垃圾收集过程中可能会产生较长的停顿(
Stop-The-World状态)。

虽然在收集垃圾过程中需要暂停所有其他的工作线程,但是它简单高效,对于限定单个CPU环境来说,没有线程交互的开销可以获得最高的单线程垃圾收集效率,因此Serial垃圾收集器依然是java虛拟机运行在Client模式下默认的新生代垃圾收集器。

对应JVM参数是: -XX:+UseSerialGC

开启后会使用: **Serial(Young区用) + Serial Old(Old区用)**的收集器组合:表示新生代、老年代都会使用串行回收收集器,新生代使用复制算法,老年代使用标记-整理算法。

ParNew收集器

ParNew是Serial收集器的升级版,将单线程进行垃圾回收升级为多线程进行垃圾回收,但是依旧会Stop The World。

ParNew收集器其实就是Serial收集器新生代的并行多线程版本,最常见的应用场景是配合老年代的CMS GC工作,其余的行为和
Serial收集器完全一样,ParNew垃圾收集器在垃圾收集过程中同样也要暂停所有其他的工作线程。它是很多java虚拟机运行在Server
模式下新生代的默认垃圾收集器。

常用对应JVM参数: -XX:+UseParNewGC

启用ParNew收集器,只影响新生代的收集,不影响老年代
开启。上述参数后,会使用: ParNew(Young区用) + Serial Old的收集器组合,新生代使用复制算法,老年代采用标记-整理算法。

但是,ParNew+Tenured这样的搭配,java8已经不再被推荐。

Parallel收集器

Parallel Scavenge收集器类似ParNew也是一个新生代垃圾收集器,使用复制算法,也是一个并行的多线程的垃圾收集器,俗称吞吐
量优先收集器
。一句话:串行收集器在新生代和老年代的并行化

首先先科普下什么是吞吐量:
吞吐量(Thoughput)=运行用户代码时间(运行用户代码时间+垃圾收集时间),也即比如程序运行100分钟,垃圾收集时间1分钟,
吞吐量就是99%)。

Parallel收集器重点关注的是:
可控制的高吞吐量意味着高效利用CPU的时间,它多用于在后台运算而不需要太多交互的任务。

**自适应调节策略也是Parallel Scavenge收集器与ParNew收集器的-一个重要区别。**自适应调节策略:虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间(-XX:MaxGCPauseMillis)或最大的吞吐量。

常用JVM参数: -XX:+UseParallelGC或-XX:+UseParallelOldGC(可互相激活)使用Parallel Scanvenge收集器

开启该参数后:使用Parallel收集器+Parallel Old的组合。新生代使用复制算法,老年代使用标记-整理算法。

Serial Old收集器

SerialOlid是Serial垃圾收集器老年代版本,它同样是个单线程的收集器,使用标记-整理算法,这个收集器也主要是运行在Client默
的java虚拟机默认的年老代垃圾收集器。

在Server模式下,主要有两个用途(了解,版本已经到8及以后): .
1.在JDK1.5之前版本中与新生代的Parallel Scavenge收集器搭配使用。 ( Parallel Scavenge + Serial Old )
2.作为老年代版中使用CMS收集器的后备垃圾收集方案

Parallel Old收集器

Parallel Old收集器是Parallel Scavenge的老年代版木,使用多线程的标记-整理算法,Parallel Old收集器在JDK1.6才开始提供。
在JDK1.6之前,新生代使用Parallel Scavenge收集器只能搭配年老代的Serial Old收集器,只能保证新生代的吞吐量优先,无法保
证整体的吞吐量。在JDK1.6之前(Parallel Scavenge + Serial Old )
Parallel Old正是为了在年老代同样提供吞吐量优先的垃圾收集器,如果系统对吞吐量要求比较高,JDK1.8后可以优先考虑新生代
Parallel Scavenge和年老代Parallel Old收集器的搭配策略。在 JDK1.8及后(Parallel Scavenge + Parallel Old )
JVM常用参数:
-XX:+UseParallelOldGC使用Parallel Old收集器,设置该参数后,新生代Parallel+老年代Parallel Old

CMS(Concurrent Mark Sweep)

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

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

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

Concurrent Mark Sweep并发标记清除,并发收集低停顿,并发指的是与用户线程一起执行。

启该收集器的JVM参数: -XX:+UseConcMarkSweepGC 开启该参数后会自动将-XX:+UseParNewGC打开
开启该参数后,使用ParNew(Young区用) + CMS(Old区用) + Serial Old的收集器组合,Serial Old将作为CMS出错的后备收集器

CMS收集器的运行过程分为下列4步:

**初始标记:**标记GC Roots能直接关联的对象。速度很快但是存在Stop The World。
**并发标记:**进行GC Roots Tracing 的过程,找出存活对象且用户线程可并发执行。
**重新标记:**为了修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录。仍然存在Stop The World问题。
**并发清除:**对标记的对象进行清除回收。

**CMS优点:**并发收集低停顿
缺点:
1.浮动垃圾:由于CMS并发清理阶段用户线程还在运行着,伴随程序运行自然会有新垃圾产生,这部分垃圾得标记过程之后,所以CMS无法在当收集中处理掉他们,只好留待下一次GC清理掉,这一部分垃圾称为浮动垃圾。在jdk1.5默认设置下,CMS收集器当老年代使用了68%的空间就会被激活,可以通过-XX:CMSInitialOccupancyFraction的值来提高触发百分比,在jdk1.6中CMS启动阈值提升到了92%,要是CMS运行期间预留的内存无法满足程序的需要,就会出现”Concurrent Mode Failure“,然后降级临时启用Serial Old收集器进行老年代的垃圾收集,这样停顿时间就很长了。所以-XX:CMSInitialOccupancyFraction设置太高容易导致大量”Concurrent Mode Failure“。

2.有空间碎片:CMS是一款基于“标记-清除”算法实现的,所以会产生空间碎片。为了解决这个问题,CMS提供了-XX:UseCMSCompactAtFullCollection开发参数用于开启内存碎片的合并整理,由于内存整理是无法并行的,所以停顿时间会变长。还有-XX:CMSFullGCBeforeCompaction,这个参数用于设置多少次不压缩Full GC后,跟着来一次带压缩的(默认为0)。

3.对CPU资源敏感。在并发标记和并发清除阶段虽然不会停止用户线程,但是会因为占用一部分cpu资源进行垃圾回收导致用户程序变慢。
CMS默认启动的回收线程数是(cpu数量+3)/4。所以CPU数量少会导致用户程序执行速度降低较多。

G1收集器

G1适用于全堆,既可以在新生代使用和老年代使用。G1与之前的收集器有很大的不同,是从不同的角度去设计的。

回想下之前的垃圾收集器的特点:
1.年轻代和老年代都是各自独立的连续的内存块。
2.年轻代Eden+from+to使用复制算法
3.老年代的收集必须扫描全部老年代内存空间。
4.都是以尽可能少而快速地执行GC为设计原则

G1收集器的设计目标是取代CMS收集器,它同CMS相比,在以下方面表现的更出色:
1、G1是一个有整理内存过程的垃圾收集器,不会产生很多内存碎片。
2、G1的Stop The World(STW)更可控,G1在停顿时间上添加了预测机制,用户可以指定期望停顿时间。

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

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

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

底层原理



G1的最大好处是化整为零,避免全内存扫描,只需要按照区域来进行扫描即可。


G1收集器大致可分为如下步骤:

**初始标记:**仅标记GC Roots能直接到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可用的Region中创建新对象。(需要线程停顿,但耗时很短。)
**并发标记:**从GC Roots开始对堆中对象进行可达性分析,找出存活对象。(耗时较长,但可与用户程序并发执行)
**最终标记:**为了修正在并发标记期间因用户程序执行而导致标记产生变化的那一部分标记记录。且对象的变化记录在线程Remembered Set Logs里面,把Remembered Set Logs里面的数据合并到Remembered Set中。(需要线程停顿,但可并行执行。)
**筛选回收:**对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。(可并发执行)

总结

到此这篇关于JVM的7种垃圾回收器(小结)的文章就介绍到这了,更多相关JVM 垃圾回收器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 图解JVM垃圾内存回收算法

    前言 首先,我们要讲的是JVM的垃圾回收机制,我默认准备阅读本篇的人都知道以下两点: JVM是做什么的 Java堆是什么 因为我们即将要讲的就是发生在JVM的Java堆上的垃圾回收,为了突出核心,其他的一些与本篇不太相关的东西我就一笔略过了 众所周知,Java堆上保存着对象的实例,而Java堆的大小是有限的,所以我们只能把一些已经用完的,无法再使用的垃圾对象从内存中释放掉,就像JVM帮助我们手动在代码中添加一条类似于C++的free语句的行为 然而这些垃圾对象是怎么回收的,现在不知道没关系,我们

  • JVM垃圾回收算法的概念与分析

    前言 在JVM内存模型中会将堆内存划分新生代.老年代两个区域,两块区域的主要区别在于新生代存放存活时间较短的对象,老年代存放存活时间较久的对象,除了存活时间不同外,还有垃圾回收策略的不同,在JVM中中有以下回收算法: 标记清除 标记整理 复制算法 分代收集算法 有了垃圾回收算法,那JVM是如果确定对象是垃圾对象的呢?判断对象是否存活JVM也会有几套自己判断算法了: 引用记数 可达性分析 有了垃圾回收和判断对象存在这两个概念后,再来逐步分析它们. JVM是如何判断对象是否存活的? 要是让开发人员来

  • 浅谈jvm中的垃圾回收策略

    java和C#中的内存的分配和释放都是由虚拟机自动管理的,此前我已经介绍了CLR中GC的对象回收方式,是基于代的内存回收策略,其实在java中,JVM的对象回收策略也是基于分代的思想.这样做的目的就是为了提高垃圾 回收的性能,避免对堆中的所有对象进行检查时所带来的程序的响应的延迟,因为jvm执行GC时,会stop the word,即终止其它线程的运行,等回收完毕,才恢复其它线程的操作.基于分代的思想是:jvm在每一次执行垃圾收集器时,只是对一小部分内存 对象引用进行检查,这一小部分对象的生命周

  • 快速理解Java垃圾回收和jvm中的stw

    Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外).Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与JVM交互:这些现象多半是由于gc引起. GC时的Stop the World(STW)是大家最大的敌人.但可能很多人还不清楚,除了GC,JVM下还会发生停顿现象. JVM里有一条特殊的线程--VM Threads,专门用来执行一些特殊的VM Operation

  • 浅析JVM垃圾回收的过程

    JVM垃圾回收的算法很多,但是不管是哪种算法,在进行GC时大致的流程都是差不多的,主要有以下3个过程: 1. 枚举根节点 这个过程主要是找到所有的GC Roots对象,这些对象一般发生在JVM虚拟机栈栈帧.常量池中的静态对象.方法区中静态类属性引用.本地方法栈中引用的对象.这个过程会发生STW,所有的线程均运行到安全区域(Safe Region)才开始执行. 通常有两种算法: 引用计数法:每个对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就+1:当引用失效时,计数器值就-1:任何时刻

  • 详解Java内存管理中的JVM垃圾回收

    一.概述 相比起C和C++的自己回收内存,JAVA要方便得多,因为JVM会为我们自动分配内存以及回收内存. 在之前的JVM 之内存管理 中,我们介绍了JVM内存管理的几个区域,其中程序计数器以及虚拟机栈是线程私有的,随线程而灭,故而它是不用考虑垃圾回收的,因为线程结束其内存空间即释放. 而JAVA堆和方法区则不一样,JAVA堆和方法区时存放的是对象的实例信息以及对象的其他信息,这部分是垃圾回收的主要地点. 二.JAVA堆垃圾回收 垃圾回收主要考虑的问题有两个:一个是效率问题,一个是空间碎片问题.

  • JVM的垃圾回收机制详解和调优

    文章来源:matrix.org.cn 作者:ginger547 1.JVM的gc概述 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作. 在充分理解了垃圾收集算法和执行过程后,才能有效的优化它的性能.有些垃圾收集专用于特殊的应用程序.比如,实时应用程序主要是为了避免垃圾收集中断,而大多数OLTP应用程序则注重整体效率.理解了应用程序的工作负荷

  • JVM垃圾回收原理解析

    概述 Java运行时区域中,程序计数器,虚拟机栈,本地方法栈三个区域随着线程的而生,随线程而死,这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收问题.而Java堆和方法区则不一样,一个接口的多个实现类需要的内存不一样,一个方法的多个分支需要的内存可能也不一眼,我们只有在运行期,才能知道会创建的对象,这部分的内存分配和回收,是垃圾回收器所关注的.垃圾回收器需要完成三个问题:那些内存需要回收:什么时候回收以及如何回收. 那些垃圾需要回收 垃圾回收的基本思想是考察一个对象的可达性,即从根节点

  • JVM的7种垃圾回收器(小结)

    垃圾回收算法和垃圾回收器 对于JVM的垃圾回收算法有复制算法.标记清除.标记整理. 用阳哥的话就是:这些算法只是天上飞的理念,是一种方法论,但是真正的垃圾回收还需要有落地实现,所以垃圾回收器应运而生. JVM回收的区域包括方法区和堆,jvm对于不同区域不同的特点采用分代收集算法,比如因为所有的对象都是在Eden区进行分配,并且大部分对象的存活时间都不长,都是"朝生夕死"的,每次新生代存活的对象都不多,所以新采取复制算法:而jvm默认是新生代的对象熬过15次GC才能进入老年代,所以老年代

  • G1垃圾回收器在并发场景调优详解

    目录 序言 G1概览 1.最大堆大小 2.Region大小 3.获取默认值 三种GC模式 1.新生代回收 2.混合回收 3.Full GC 默认参数 1.堆内存 2.新生代内存回收 3.混合回收 垃圾在堆中流转 1.对象如何进入老年代 (1)大对象直接到老年代 (2)动态年龄判断 2.高并发加速进入老年代 调优步骤 1.设置垃圾回收器 2.设置堆大小 3.元空间设置 4.GC停顿时间 5.新生代大小 调优实践 1.频繁的YGC 2.频繁的Mixed GC (1)大对象 (2)元空间 3.Full

  • 浅析JVM的垃圾回收器

    JVM的GC经过多年的发展,大家对Minor GC.major GC的理解并不完全一致,所以我不打算在本文中使用这个概念.我把GC大概分为一下4类: Young GC:只是负责回收年轻代对象的GC: Old GC:只是负责回收老年代对象的GC: Full GC:回收整个堆的对象,包括年轻代.老年代.持久带: Mixed GC:回收年轻代和部分老年代的GC (G1): 因为笔者目前使用G1还是比较少的,所以本文不打算将G1. 垃圾回收器算法 目前主流垃圾回收器都采用的是可达性分析算法来判断对象是否

  • WordPress过滤垃圾评论的几种主要方法小结

    由于个人博客小站的空间与mysql空间往往有限,共享服务器资源也有限,所以垃圾评论一定要拦截在写入数据库之外. 更可气的是看到空间的统计,很几千的IP访问,但基本上都是这个垃圾评论的IP,所以实在不能忍 网上找了一些方法,主要有三个,如果将这三个一块使用基本上就可以拦截绝大多数垃圾评论 一.使用Akismet插件(https://wordpress.org/plugins/akismet/),后台申请一个免费的key,可以拦截99%的垃圾评论,但是这个插件还是会将垃圾评论写入数据库的,一会几千条

  • 浅谈关于Java的GC垃圾回收器的一些基本概念

    一.基本回收算法 1. 引用计数(Reference Counting) 比较古老的回收算法.原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回收时,只用收集计数为0的对象.此算法最致命的是无法处理循环引用的问题. 2. 标记-清除(Mark-Sweep) 此算法执行分两阶段.第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除.此算法需要暂停整个应用,同时,会产生内存碎片. 3. 复制(Copying) 此算法把内存空间划为两个相等的区域

  • 一篇带你入门Java垃圾回收器

    目录 1 垃圾回收算法 1-1 标记清除算法 算法思想 1-2 标记整理算法 1-3 复制算法 2 JVM分代回收算法 2-1 概述 2-2 分代垃圾回收示例 2-3 分代垃圾回收的总结 对象首先分配在伊甸园区域 2-5 垃圾回收案例分析 2 垃圾回收器 2-1 垃圾回收器概述 2-2 串行垃圾回收器 2-3 吞吐量优先的垃圾回收器 2-4 响应时间优先的垃圾回收器(CMS垃圾回收器) 总结: 第一阶段:串行垃圾回收器:jdk1.3.1之前Java虚拟机仅仅只支持Serial收集器 第二阶段:并

  • Java中垃圾回收器GC对吞吐量的影响测试

    在看内存管理术语表的时候偶然发现了"Pig in the Python(注:有点像中文里的贪心不足蛇吞象)"的定义,于是便有了这篇文章.表面上看,这个术语说的是GC不停地将大对象从一个分代提升到另一个分代的情景.这么做就好比巨蟒整个吞食掉它的猎物,以至于它在消化的时候都没办法移动了. 在接下来的这24个小时里我的头脑中充斥着这个令人窒息的巨蟒的画面,挥之不去.正如精神病医生所说的,消除恐惧最好的方法就是说出来.于是便有了这篇文章.不过接下的故事我们要讲的不是蟒蛇,而是GC的调优.我对天

  • Java垃圾回收器的方法和原理总结

    什么是Java垃圾回收器 Java垃圾回收器是Java虚拟机(JVM)的三个重要模块(另外两个是解释器和多线程机制)之一,为应用程序提供内存的自动分配(Memory Allocation).自动回收(Garbage Collect)功能,这两个操作都发生在Java堆上(一段内存快).某一个时点,一个对象如果有一个以上的引用(Rreference)指向它,那么该对象就为活着的(Live),否则死亡(Dead),视为垃圾,可被垃圾回收器回收再利用.垃圾回收操作需要消耗CPU.线程.时间等资源,所以容

  • 简单了解Java垃圾回收器的种类

    在这篇教程中我们将学习几种现有的垃圾回收器.在Java中,垃圾回收是一个自动的进程可以替代程序员进行内存的分配与回收这些复杂的工作.这篇是垃圾回 收教程系列的第三篇,在前面的第2部分我们看到了在Java中垃圾回收是如何工作的,那是篇有意思的文章,我推荐你去看一下.第一部分介绍了Java的垃圾回收,主要有JVM体系结构,堆内存模型和一些Java术语. Java有四种类型的垃圾回收器: 串行垃圾回收器(Serial Garbage Collector) 并行垃圾回收器(Parallel Garbag

  • SpringBoot项目调优及垃圾回收器的比较详解

    一.SpringBoot项目在外部Tomcat启动时加载两次 如下所示,spring标志出现两次(截取部分代码) . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|=====

随机推荐