JVM学习日志(十三) G1垃圾回收流程 及 垃圾回收器总结

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: G1垃圾回收流程 及 垃圾回收器 总结 简述

G1垃圾回收流程

image-20230506113751177.png

G1的垃圾回收流程主要是从新生代回收开始,新生代回收与并发标记再打混合回收,接下来我们就先说第一个新生代回收

G1 Young Collection

当我们的程序启动刚开始的时候,会默认分配新生代5%的空间,这里我们假设分配了8个Region给Eden, 1个Region给Survior(只是为了画图方便,实际上可能Eden对应了有好几十甚至上百个Region),那么对应的初始内存分配如下:

image-20230506114004719.png

那么当我们的Eden区域装满,还是会触发新生代的GC,那么新生代的GC还是会通过复制算法来进行垃圾回收,同时系统进入到"Stop The World"状态,然后把Eden区中的对应的Region里存货的对象拷贝到S1对应的Region中,接着回收掉Eden对应的Region中的垃圾对象

注意并不是Eden区一满就会立马触发新生代GC,G1会计算现在Eden区回收大概需要多久的时间,如果远远小于默认的200ms,那么就会继续增加新生代的Region,继续存放新的对象,直到下一次Eden区满再计算回收时间,如果时间接近200ms或者设置的值,则触发MionrGC

需要注意的是:

再触发空间担保的情况下,G1是不会将大对象直接存储到堆空间中,而是有专门的大对象存储的区域Humongous

Humongous区域的大对象什么时候会被回收呢,其实很简单,再新生代和老年代的对象回收的时候,就会顺带着堆大对象一并回收,所以这就是G1内存模型下对大对象的分配和回收的策略

注意

再G1进行新生代垃圾回收的同时还会做一件事情就是"初始标记":仅仅只是标记一下GCRoots能直接关联到的对象,对下一阶段并发标记做准备(跟之前的CMS垃圾回收过程类似)

当G1新生代垃圾回收结束之后,紧接着开始进入并发标记阶段,从GCRoot开始对堆中的对象进行可达性分析,递归扫描整个堆里的对象图,找出来要回收的对象,这阶段耗时比较长,但是可与用户程序并发执行

而且JVM会对并发标记阶段对对象做出的一些修改记录起来,比如那个对象被新建了,那个对象失去引用了

G1 Mixed Conllection

G1有一个参数:"-XX:InitiatingHeapOccupancyPercent"默认值是45%

也就是说:当老年代的大小占据了堆内存的45%的Region时,此时就会触发一个新生代和老年代的混合回收阶段,对ES0H进行全面回收

该阶段一旦触发会导致系统进入STW,同时进行最后一个标记

最终标记阶段:

会根据并发标记阶段记录的对象修改,最终标记那些对象是存活,那些对象是垃圾

此时老年代也是根据标记-复制算法来进行回收,会将标记存活的对象拷贝到新的Region中作为老年代区域

注意我们上面说过得一个参数: -XX:MaxGCPauseMillis=time指定收集的停顿时间,默认是200ms

由于混合回收是一个比较耗时的操作,那么根据G1的特点可以指定收集停顿时间,为了保证停顿时间这个目标,JVM会从新生代,老年代,以及大对象H区挑选一部分Region进行拷贝回收,如果回收不完,后续在进行回收,一部分一部分回收直到回收完毕,但是一次回收的停顿时长保证再200MS

这里有一个参数"-XX: G1MixedGCCountTarget",可以设置在一次回合回收的过程中,最后一个阶段执行几次混合回收,默认值是8次,这样设置的目的也是能让每次会后停顿的时长记得到保证同时又能间隙的让系统接着运行

同时还有一个参数"-XX:G1HeapWastePercent",默认值是5%,意思是当回合回收的时候,一旦空闲出来的Region的数量达到了堆内存的5%,此时就会立即停止混合回收

FullGC

当在进行混合回收的过程中,由于无论是新生代还是老年代都是基于复制算法进行的,都需要将各个Region中的存活独享拷贝到别的Region中,此时如果一旦出现拷贝的过程中发现没有空闲的Region可以进行存储了,就会触发一次失败,那么这时候系统会立马切换为我们的Seiral收集器进行单线程标记,清理,和压缩整理,该过程就变得非常慢了

垃圾回收器总结

SerialGC

新生代内存不足发生的垃圾收集-minor Gc

老年代内存不足发生的垃圾收集 full gc

parallelGC\Parnew

新生代内存不足发生的垃圾收集 minor GC

老年代内存不足发生的垃圾收集 full gc

CMS

新生代内存不足发生的垃圾收集: minor gc

老年代内存92%开始回收,触发Concurrent Mode Failure 时触发Full GC

G1

新生代内存不足发生的垃圾收集 minor gc

老年代内存不足,无多余Region可供拷贝 触发 Full gc

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
6月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
593 55
|
7月前
|
调度
FreeRTOS学习日志 - 第一天
这就是我的FreeRTOS学习日志 - 第一天的内容,明天继续探索这片实时操作系统的广阔海洋。+
126 12
|
6月前
|
缓存 算法 Java
JVM深入原理(八)(一):垃圾回收
弱引用-作用:JVM中使用WeakReference对象来实现软引用,一般在ThreadLocal中,当进行垃圾回收时,被弱引用对象引用的对象就直接被回收.软引用-作用:JVM中使用SoftReference对象来实现软引用,一般在缓存中使用,当程序内存不足时,被引用的对象就会被回收.强引用-作用:可达性算法描述的根对象引用普通对象的引用,指的就是强引用,只要有这层关系存在,被引用的对象就会不被垃圾回收。引用计数法-缺点:如果两个对象循环引用,而又没有其他的对象来引用它们,这样就造成垃圾堆积。
181 0
|
6月前
|
算法 Java 对象存储
JVM深入原理(八)(二):垃圾回收
Java垃圾回收过程会通过单独的GC线程来完成,但是不管使用哪一种GC算法,都会有部分阶段需要停止所有的用户线程。这个过程被称之为StopTheWorld简称STW,如果STW时间过长则会影响用户的使用。一般来说,堆内存越大,最大STW就越长,想减少最大STW,就会减少吞吐量,不同的GC算法适用于不同的场景。分代回收算法将整个堆中的区域划分为新生代和老年代。--超过新生代大小的大对象会直接晋升到老年代。
148 0
|
8月前
|
缓存 监控 算法
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略
|
8月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
11月前
|
算法 网络协议 Java
【JVM】——GC垃圾回收机制(图解通俗易懂)
GC垃圾回收,标识出垃圾(计数机制、可达性分析)内存释放机制(标记清除、复制算法、标记整理、分代回收)
|
11月前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
26天前
|
存储 缓存 Java
我们来说一说 JVM 的内存模型
我是小假 期待与你的下一次相遇 ~
173 4
|
1月前
|
存储 缓存 算法
深入理解JVM《JVM内存区域详解 - 世界的基石》
Java代码从编译到执行需经javac编译为.class字节码,再由JVM加载运行。JVM内存分为线程私有(程序计数器、虚拟机栈、本地方法栈)和线程共享(堆、方法区)区域,其中堆是GC主战场,方法区在JDK 8+演变为使用本地内存的元空间,直接内存则用于提升NIO性能,但可能引发OOM。