JVM系列篇:深入剖析G1收集器+回收流程+推荐用例

Stella981
• 阅读 561

本系列会持续更新

JVM系列篇:深入剖析G1收集器+回收流程+推荐用例

金三已经过去一半了,即将进入面试的高峰期。在BAT面试中,JVM基本都是必考的系列。你至少需要掌握:JVM内存模型与JVM参数详细配置、JVM的4种垃圾回收算法、垃圾回收机制等(文末直达)

以及今天重点谈到的JVM垃圾回收算法的实现:JVM垃圾收集器

我先从JVM收集器的发展过程谈起,然后再聚焦在G1收集器,从G1的内存模型,再到G1的回收流程,最后再谈谈G1的实际应用场景。

一、JVM垃圾收集器发展历程

JVM垃圾收集器发展历程

第一阶段,Serial(串行)收集器

在jdk1.3.1之前,java虚拟机仅仅能使用Serial收集器。 Serial收集器是一个单线程的收集器,但它的“单线程”的意义并不仅仅是说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。

第二阶段,Parallel(并行)收集器

Parallel收集器也称吞吐量收集器,相比Serial收集器,Parallel最主要的优势在于使用多线程去完成垃圾清理工作,这样可以充分利用多核的特性,大幅降低gc时间。

第三阶段,CMS(并发)收集器

CMS收集器在Minor GC时会暂停所有的应用线程,并以多线程的方式进行垃圾回收。在Full GC时不再暂停应用线程,而是使用若干个后台线程定期的对老年代空间进行扫描,及时回收其中不再使用的对象。

第四阶段,G1(并发)收集器

G1收集器(或者垃圾优先收集器)的设计初衷是为了尽量缩短处理超大堆(大于4GB)时产生的停顿。相对于CMS的优势而言是内存碎片的产生率大大降低。

二、JVM垃圾收集器种类

JVM系列篇:深入剖析G1收集器+回收流程+推荐用例

JVM垃圾收集器

1.新生代

  • Serial (第一代)
  • PraNew (第二代)
  • Parallel Scavenge (第三代)
  • G1收集器(第四代)

2.老年代

  • Serial Old (第一代)
  • Parallel Old (第二代)
  • CMS (第三代)
  • G1收集器 (第四代)

JVM系列篇:深入剖析G1收集器+回收流程+推荐用例

详细的垃圾收集器比较,具体可以查看往期文章:7种JVM垃圾收集器特点(文末直达)。

JDK1.7后全新的JVM垃圾收集器G1收集器, 目标用于取代CMS收集器。

G1收集器概述

从JDK(1.3)开始,HotSpot团队一直努力朝着高效收集、减少停顿(STW: Stop The World)的方向努力,也贡献了从串行Serial收集器、到并行收集器Parallerl收集器,再到CMS并发收集器,乃至如今的G1在内的一系列优秀的垃圾收集器。

G1(Garbage First)垃圾收集器是当今垃圾回收技术最前沿的成果之一。早在JDK7就已加入JVM的收集器大家庭中,成为HotSpot重点发展的垃圾回收技术。同优秀的CMS垃圾回收器一样,G1也是关注最小时延的垃圾回收器,也同样适合大尺寸堆内存的垃圾收集,官方也推荐使用G1来代替选择CMS。

  1. G1收集器的最大特点
  • G1最大的特点是引入分区的思路,弱化了分代的概念。
  • 合理利用垃圾收集各个周期的资源,解决了其他收集器甚至CMS的众多缺陷。

2. G1相比较CMS的改进

  • 算法: G1基于标记-整理算法, 不会产生空间碎片,分配大对象时不会无法得到连续的空间而提前触发一次FULL GC。
  • 停顿时间可控: G1可以通过设置预期停顿时间(Pause Time)来控制垃圾收集时间避免应用雪崩现象。
  • 并行与并发:G1能更充分的利用CPU,多核环境下的硬件优势来缩短stop the world的停顿时间。

3. CMS和G1的区别

  • CMS中,堆被分为PermGen,YoungGen,OldGen;而YoungGen又分了两个survivo区域。在G1中,堆被平均分成几个区域(region),在每个区域中,虽然也保留了新老代的概念,但是收集器是以整个区域为单位收集的。
  • G1在回收内存后会马上同时做合并空闲内存的工作、而CMS默认是在STW(stop the world)的时候做。
  • G1会在Young GC中使用、而CMS只能在O区使用。

4. G1收集器的应用场景

G1垃圾收集算法主要应用在多CPU大内存的服务中,在满足高吞吐量的同时,尽可能的满足垃圾回收时的暂停时间。

就目前而言、CMS还是默认首选的GC策略、可能在以下场景下G1更适合:

  • 服务端多核CPU、JVM内存占用较大的应用(至少大于4G)
  • 应用在运行过程中会产生大量内存碎片、需要经常压缩空间
  • 想要更可控、可预期的GC停顿周期,防止高并发下应用雪崩现象

G1的堆内存算法

  1. G1之前的JVM内存模型

JVM系列篇:深入剖析G1收集器+回收流程+推荐用例

  • 新生代:伊甸园区(eden space) + 2个幸存区
  • 老年代
  • 持久代(perm space):JDK1.8之前
  • 元空间(metaspace):JDK1.8之后取代持久代

2. G1收集器的内存模型

JVM系列篇:深入剖析G1收集器+回收流程+推荐用例

1) G1堆内存结构

堆内存会被切分成为很多个固定大小区域(Region),每个是连续范围的虚拟内存。

堆内存中一个区域(Region)的大小可以通过-XX:G1HeapRegionSize参数指定,大小区间最小1M、最大32M,总之是2的幂次方。

默认把堆内存按照2048份均分。

2) G1堆内存分配

每个Region被标记了E、S、O和H,这些区域在逻辑上被映射为Eden,Survivor和老年代。

存活的对象从一个区域转移(即复制或移动)到另一个区域。区域被设计为并行收集垃圾,可能会暂停所有应用线程。

如上图所示,区域可以分配到Eden,survivor和老年代。此外,还有第四种类型,被称为巨型区域(Humongous Region)。Humongous区域是为了那些存储超过50%标准region大小的对象而设计的,它用来专门存放巨型对象。如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。

G1回收流程

在执行垃圾收集时,G1以类似于CMS收集器的方式运行。

  1. G1收集器的阶段分以下几个步骤:

JVM系列篇:深入剖析G1收集器+回收流程+推荐用例

1)G1执行的第一阶段:初始标记(Initial Marking )

这个阶段是STW(Stop the World )的,所有应用线程会被暂停,标记出从GC Root开始直接可达的对象。

2)G1执行的第二阶段:并发标记

从GC Roots开始对堆中对象进行可达性分析,找出存活对象,耗时较长。当并发标记完成后,开始最终标记(Final Marking )阶段

3)最终标记

标记那些在并发标记阶段发生变化的对象,将被回收。

4)筛选回收

首先对各个Regin的回收价值和成本进行排序,根据用户所期待的GC停顿时间指定回收计划,回收一部分Region。

最后,G1中提供了两种模式垃圾回收模式,Young GC和Mixed GC,两种都是Stop The World(STW)的。

G1的GC模式

  1. YoungGC年轻代收集

在分配一般对象(非巨型对象)时,当所有eden region使用达到最大阀值并且无法申请足够内存时,会触发一次YoungGC。每次younggc会回收所有Eden以及Survivor区,并且将存活对象复制到Old区以及另一部分的Survivor区。

YoungGC的回收过程如下:

  • 根扫描,跟CMS类似,Stop the world,扫描GC Roots对象。
  • 处理Dirty card,更新RSet.
  • 扫描RSet,扫描RSet中所有old区对扫描到的young区或者survivor去的引用。
  • 拷贝扫描出的存活的对象到survivor2/old区
  • 处理引用队列,软引用,弱引用,虚引用

2. mixed gc

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

G1没有fullGC概念,需要fullGC时,调用serialOldGC进行全堆扫描(包括eden、survivor、o、perm)。

G1的推荐用例

G1的第一个重要特点是为用户的应用程序的提供一个低GC延时和大内存GC的解决方案。这意味着堆大小6GB或更大,稳定和可预测的暂停时间将低于0.5秒。

如果应用程序使用CMS或ParallelOld垃圾回收器具有一个或多个以下特征,将有利于切换到G1:

  • Full GC持续时间太长或太频繁
  • 对象分配率或年轻代升级老年代很频繁
  • 不期望的很长的垃圾收集时间或压缩暂停(超过0.5至1秒)

注意:如果你正在使用CMS或ParallelOld收集器,并且你的应用程序没有遇到长时间的垃圾收集暂停,则保持与您的当前收集器是很好的,升级JDK并不必要更新收集器为G1。

觉得不错请点赞支持下。

----end----

以下是JVM系列文章集合,感兴趣不妨深入了解,扩充知识栈:

JVM的4种垃圾回收算法、垃圾回收机制与总结
7种JVM垃圾收集器特点,优劣势、及使用场景
深入详解JVM内存模型与JVM参数详细配置
JVM性能调优的6大步骤,及关键调优参数详解

深入剖析G1收集器+回收流程+推荐用例

作者Mike,10年+程序员。主要分享:BAT 面试、Java 架构、招聘资讯等内容。

曾先后就职于淘宝、盛大、百度、携程 ,历任高级研发工程师、研发经理、架构师、事业部 CTO。

坚持写文2年多,原创内容400篇,目前粉丝总数7万+,欢迎留言或进我的个人群179961551交流技术、分享面试机会,拒绝广告,我也会在群内不定期交流、探讨~

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
从原理聊JVM(一):染色标记和垃圾回收算法
本篇介绍了JVM中垃圾回收器相关的基础知识,后续会深入介绍CMS、G1、ZGC等不同垃圾收集器的运作流程和原理,欢迎关注。
Wesley13 Wesley13
2年前
JAVA工程师成神道路
一、基础篇1.1JVM1.1.1.Java内存模型,Java内存管理,Java堆和栈,垃圾回收http://www.jcp.org/en/jsr/detail?id133http://ifeve.com/jmmfaq/1.1.2.了解JVM各种参数及调优1.1.3.
Wesley13 Wesley13
2年前
Java工程师成神之路~
一、基础篇1.1JVM1.1.1.Java内存模型,Java内存管理,Java堆和栈,垃圾回收http://www.jcp.org/en/jsr/detail?id133http://ifeve.com/jmmfaq/1.1.2.了解JVM各种参数及调优1.1.3.
Stella981 Stella981
2年前
JVM系列篇:深入详解JVM内存模型与JVM参数详细配置
本系列会持续更新。!(https://oscimg.oschina.net/oscnet/4d447fcd24dbd05920ecc47f33e460b55bc.jpg)JVM基本是BAT面试必考的内容,今天我们先从JVM内存模型开启详解整个JVM系列,希望看完整个系列后,可以轻松通过BAT关于JVM的考核。
Wesley13 Wesley13
2年前
Java工程师成神之路
一、基础篇1.1JVM1.1.1.Java内存模型,Java内存管理,Java堆和栈,垃圾回收http://www.jcp.org/en/jsr/detail?id133http://ifeve.com/jmmfaq/1.1.2.了解JVM各种参数及调优
Stella981 Stella981
2年前
JVM系列【6】GC与调优3
JVM系列笔记目录虚拟机的基础概念class文件结构class文件加载过程jvm内存模型JVM常用指令GC与调优调优前的基础概念1.吞吐量:用户代码时间/(用户代码执行时间垃圾回收时间)2.响应时间:STW越短,响应时间越好3.
Stella981 Stella981
2年前
JVM系列篇:7种JVM垃圾收集器特点,优劣势、及使用场景
本系列会持续更新。!(https://oscimg.oschina.net/oscnet/945dbe48630eb4284fea936b19161c0f08a.jpg)今天继续JVM的垃圾回收器详解,如果说垃圾收集算法是JVM内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。一、常见的垃圾收集器
Stella981 Stella981
2年前
JVM架构体系与GC命令小总结
!(https://oscimg.oschina.net/oscnet/052a011b9ad19376d76daa6b6dcb82fa032.png)1.Overview2.JVM架构体系1)垃圾回收对象存活性判断垃圾回收算法垃圾回收器(回收算法的具体实现)
京东云开发者 京东云开发者
6个月前
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了