1、G1垃圾回收器概述

原文地址

前言

开始学习前,抛出两个常见面试问题:1.G1的回收原理是什么?为什么G1比传统的GC回收性能好?2.为什么G1如此完美仍然会有ZGC?简单的回顾下CMS垃圾回收机制,下面介绍了一个极端的场景(而且是经常发生的) 在发生Minor GC时,由于Survivor区已经放不下了,多出的对象只能提升(Promotion)到老年代。但是此时老年代因为空间碎片的缘故,会发生Concurrent mode failure的错误。这个时候,就需要降级为Serial Old垃圾回收器进行收集。这就是比concurrent mode failure 更加严重的promotion failed的问题。一个简单的Minor,竟然能演化成耗时最长的Full GC。最要命的是,这个停顿时间是不可预知的。有没有一种方法,能够首先定义一个停顿时间,然后反向推算收集内容呢?就像是领导在年初制定KPI一样,分配的任务多久多干些,任务少就少干点。类似需要徒步一段很长的路,然后在路中有多个里程碑,到达一个后可以休息一会。G1的思路说起来类似,它不要求每次都把垃圾清理的干干净净,只是努力做它认为对的事情。我们要求G1,在任意1秒的时间内,停顿不得超过10ms,这就是在给它制定KPI。G1会尽量达成这个目标,它能够推算出本次要收集的大体区域,以增量的方式完成收集。这也是使用G1垃圾回收器不得不设置的一个参数:-XX:MaxGCPauseMilis=10

简介

G1(Garbage First)垃圾收集器是当今垃圾回收技术最前沿的成果之一。早在JDK7就已加入JVM的收集器大家庭中,成为HotSpot重点发展的垃圾回收技术。同优秀的CMS垃圾回收器一样,G1也是关注最小时延的垃圾回收器,也同样适合大尺寸堆内存的垃圾收集,官方也推荐使用G1来代替选择CMS。G1最大的特点是引入分区的思路,弱化了分代的概念,合理利用垃圾收集各个周期的资源,解决了其他收集器甚至CMS的众多缺陷。

为解决CMS算法产生空间碎片和其它一系列的问题缺陷,HotSpot提供了另外一种垃圾回收策略,G1(Garbage First)算法,通过参数-XX:+UseG1GC来启用,该算法在JDK 7u4版本被正式推出,官网对此描述如下:

The Garbage-First (G1) collector is a server-style garbage collector, targeted for multi-processor machines with large memories. It meets garbage collection (GC) pause time goals with a high probability, while achieving high throughput. The G1 garbage collector is fully supported in Oracle JDK 7 update 4 and later releases. The G1 collector is designed for applications that:•Can operate concurrently with applications threads like the CMS collector.•Compact free space without lengthy GC induced pause times.•Need more predictable GC pause durations.•Do not want to sacrifice a lot of throughput performance.•Do not require a much larger Java heap.

官网的上述翻译如下:

G1垃圾收集算法主要应用在多CPU大内存的服务中,在满足高吞吐量的同时,竟可能的满足垃圾回收时的暂停时间,该设计主要针对如下应用场景:

•垃圾收集线程和应用线程并发执行,和CMS一样•空闲内存压缩时避免冗长的暂停时间•应用需要更多可预测的GC暂停时间•不希望牺牲太多的吞吐性能•不需要很大的Java堆 (翻译的有点虚,多大才算大?)

为什么叫G1?

G1的目标是用来干掉CMS的,它同样是一款软实时垃圾回收器。相比CMS,G1的使用更加人性化。比如,CMS垃圾回收器的相关参数有72个,而G1的参数只有26个。G1的全称是GarbageFirst GC,为了达成上面制定的KPI,它和前面介绍的垃圾回收器,在对堆的划分上有一些不同。其它的回收器,都是对某个年代的整体收集,收集时间上自然不好控制。G1把堆切成了很多份,把每一份当作一个小目标,每一份收集时间自然是很好控制的。那么题又来了:G1有年轻代和老年代区分吗?


如图所示,G1也是有Eden区和Survivor区的概念的,只不过它们在内存上不是连续的,而是由一小份一小份组成的。这一小份区域的大小是固定的,名字叫做小堆区(Region)。小堆区可以是Eden也可以是Survivor区,还可以是Old区,所以G1的年轻代和老年代的概念都是逻辑上的。每一块Region,大小都是一致的,它的数值在1M-32M字节之间的一个2的幂值数。但假如我的对象太大,一个Region放不下怎们办?注意图中有一块很大的黄色区域,叫Humongous Region,大小超过Region 50%的对象,将会在这里分配。Region的大小,可以通过参数进行设置:-XX:G1HeapRegionSize=M 那么回收的时候,到底回收那些小堆区呢?是随机的吗?当然不是,事实上,垃圾最多的小堆区,会被优先回收,这也是G1名字的由来。

堆内存结构

CMS

以往的垃圾回收算法,如CMS,使用的堆内存结构如下:


1.新生代:eden space + 2个survivor2.老年代:old space3.持久代:1.8之前的perm space4.元空间:1.8之后的metaspace

以上这些space必须是地址连续的空间。

G1

在G1算法中,采用了另外一种完全不同的方式组织堆内存,堆内存被划分为多个大小相等的内存块(Region),每个Region是逻辑连续的一段内存,结构如下:


每个Region被标记了E、S、O和H,说明每个Region在运行时都充当了一种角色,其中H是以往算法中没有的,它代表Humongous,这表示这些Region存储的是巨型对象(humongous object,H-obj),当新建对象大小超过Region大小一半时,直接在新的一个或多个连续Region中分配,并标记为H。

Region

堆内存中一个Region的大小可以通过-XX:G1HeapRegionSize参数指定,大小区间只能是1M、2M、4M、8M、16M和32M,总之是2的幂次方,如果G1HeapRegionSize为默认值,则在堆初始化时计算Region的实际大小,具体实现如下:


默认把堆内存按照2048份均分,最后得到一个合理的大小。

GC模式

G1中提供了三种模式垃圾回收模式,young gc、mixed gc 和 full gc,在不同的条件下被触发。

young gc

发生在年轻代的GC算法,一般对象(除了巨型对象)都是在eden region中分配内存,当所有eden region被耗尽无法申请内存时,就会触发一次young gc,这种触发机制和之前的young gc差不多,执行完一次young gc,活跃对象会被拷贝到survivor region或者晋升到old region中,空闲的region会被放入空闲列表中,等待下次被使用。


mixed gc

当越来越多的对象晋升到老年代old region时,为了避免堆内存被耗尽,虚拟机会触发一个混合的垃圾收集器,即mixed gc,该算法并不是一个old gc,除了回收整个young region,还会回收一部分的old region,这里需要注意:是一部分老年代,而不是全部老年代,可以选择哪些old region进行收集,从而可以对垃圾回收的耗时时间进行控制。

那么mixed gc什么时候被触发?

先回顾一下cms的触发机制,如果添加了以下参数:

-XX:CMSInitiatingOccupancyFraction=80

-XX:+UseCMSInitiatingOccupancyOnly

当老年代的使用率达到80%时,就会触发一次cms gc。相对的,mixed gc中也有一个阈值参数 -XX:InitiatingHeapOccupancyPercent,当老年代大小占整个堆大小百分比达到该阈值时,会触发一次mixed gc.

mixed gc的执行过程有点类似cms,主要分为以下几个步骤:

1.initial mark: 初始标记过程,整个过程STW,标记了从GC Root可达的对象2.concurrent marking: 并发标记过程,整个过程gc collector线程与应用线程可以并行执行,标记出GC Root可达对象衍生出去的存活对象,并收集各个Region的存活对象信息3.remark: 最终标记过程,整个过程STW,标记出那些在并发标记过程中遗漏的,或者内部引用发生变化的对象4.clean up: 垃圾清除过程,如果发现一个Region中没有存活对象,则把该Region加入到空闲列表中

full gc

如果对象内存分配速度过快,mixed gc来不及回收,导致老年代被填满,就会触发一次full gc,G1的full gc算法就是单线程执行的serial old gc,会导致异常长时间的暂停时间,需要进行不断的调优,尽可能的避免full gc.

你可能感兴趣的:(1、G1垃圾回收器概述)