系列十三(面试)、谈谈你对G1垃圾收集器的理解

一、G1垃圾收集器

1.1、概述

        G1(Garbage-First)收集器,是一款面向服务端应用的垃圾收集器,应用在多处理器和大容量的内存环境中,在实现高吞吐量的同时,尽可能的满足垃圾收集暂停时间的要求。另外,它还具有如下特性:

(1)像CMS收集器一样,能与应用程序并发执行;

(2)整理空闲空间更快;

(3)需要更多的时间来预测GC停顿时间;

(4)不希望牺牲大量的吞吐性能;

(5)不需要更大的Java Heap;

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

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

(2)G1的STW(Stop The World)更可控,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内存区域。

1.2、G1收集器的特点

(1)G1能充分利用多CPU、多核环境硬件优势,尽量缩短STW(Stop The World);

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

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

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

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

1.3、以前垃圾收集器的特点

(1)年轻代和老年代是各自独立且连续的内存块;

(2)年轻代收集垃圾使用复制算法;

(3)老年代收集必须扫描整个老年代区域;

(4)都是以尽可能少而快速地执行GC为设计原则;

1.4、底层原理

1.4.1、Region区域化垃圾收集器

        区域化内存划片Region,整体变为了一些列不连续的内存区域,避免了全内存区的GC操作。核心思想是将整个堆内存区域分成大小相同的子区域(Region),在JVM启动时会自动设置这些子区域的大小,在堆的使用上,G1并不要求对象的存储一定是物理上连续的,只要逻辑上连续即可,每个分区也不会为某个固定地generation服务,可以按需在年轻代和老年代之间切换。启动时可以通过参数 -XX:G1HeapRegionSize=n 指定分区大小(1MB~32MB,且必须是2的幂),默认将整堆划分为2048个分区。大小范围在1MB~32MB,最多能设置2048个区域,也即能够支持的最大内存为:32MB*2048=65536MB=64G内存。Region区域化垃圾收集最大的好处是:化整为零,避免全内存扫描,只需要按照区域来进行扫描即可。

系列十三(面试)、谈谈你对G1垃圾收集器的理解_第1张图片

1.4.2、回收步骤

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

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

(2)Survivor区的数据移动到新的Survivor区,部会数据晋升到Old区;
(3)最后Eden区收拾干净了,GC结束,用户的应用程序继续执行;

系列十三(面试)、谈谈你对G1垃圾收集器的理解_第2张图片

1.4.3、4步过程

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

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

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

        系列十三(面试)、谈谈你对G1垃圾收集器的理解_第3张图片

1.5、案例

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2023/12/21 18:37
 * @Description: 演示G1垃圾收集器案例代码
 *      VM参数:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseG1GC
 */
public class GCVmOptionsMainApp {

    public static void main(String[] args) {
        String message = "欧耶,今天星期五!";
        while (true) {
            message += message + new Random().nextInt(88888888) + new Random(99999999);
        }
    }

}

1.6、常用配置参数(了解)

(1)-XX:+UseG1GC:设置垃圾收集器为G1

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

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

(4)-XX:InitiatingHeapOccupancyPercent=n  :堆占用了多少的时候就触发GC,默认是45

(5)-XX:ConcGCThreads=n :并发GC使用的线程数

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

1.7、G1 vs CMS

(1)G1不会产生内存碎片;

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

1.8、小总结

系列十三(面试)、谈谈你对G1垃圾收集器的理解_第4张图片

你可能感兴趣的:(GC系列,GC)