五、HotSpot细节实现

一、并发标记与三色标记

问题:三色标记到底发生在什么阶段,替代了什么。并发标记

1、并发标记( Concurrent Marking)

从 GC Root 开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以后 ,并发标记时有引用变动的对象 ,这些对象会漏标。

CMS和G1的并发标记阶段使用的标记清除扫秒算法占用了太长中断时间,所以用三色标记替换。

2、三色标记的概念(多线程)

在三色标记之前有一个算法叫Mark-And-Sweep(标记清除)。这个算法会给每一个对象设置一个标志位来记录对象是否被使用。最开始标识位都是0,如果发现对象可达就会设置为1,一步步下去就会呈现一个类似树状的结果。等标记的步骤完成后,会将被标记的对象统一清理,再次把所有的标记位置设置成0方便下次清理。

标记清除最大的问题是GC执行期间需要把整个程序完全暂停,不能异步进行GC操作。因为不同阶段标记清除法的标志位0和1有不同的含义,那么新增的对象无论标记成什么都有可能意外删除。对实时性要求高的系统来说,这种需要长时间挂起的标记清除算法是不可接受的。所以就需要一个算法来解决GC运行时程序长时间挂起的问题,那就是三色标记。

三色标记最大的好处就是异步,从而可以以中断时间极少的代价或者完全没有中断来进行整个GC

三色标记把对象用三种颜色标记

  • 黑色:根对象,或者这个对象及他的子对象都已经被扫描了
  • 灰色:本身已经扫描了,子对象还没扫描
  • 白色:未被扫描的对象,如果扫描完所有的对象之后,最终白色的为不可达对象,既为垃圾

3、三色标记的问题

GC并发情况下会有漏标的问题

第一步:线程1完成所有的标记,线程2还处于半完成状态

第二步:引用发成变化,B指向C变成A指向C

第三步:线程1、2都完成所有的标记,C对象是白色,被错误的回收

4、三色标记并发情况下漏标记解决方案(单线程,最终标记)

(1)cms的解决方案 incremental update 增量更新算法

CMS的三色标记发生并发标记和重新标记阶段

当一个白色对象被一个黑色对象引用,将黑色对象重新标记为灰色,让垃圾回收器重新扫描。增量更新,关注的是引用新增。

(2)G1中的解决方案 STAB (snapshot-at-the-beginning) 快照处理算法

刚开始做一个快照,当B指向C的引用消失的时候,就把这个引用推到GC的堆栈,保证C还能被GC扫描到,最重要的是要把这个引用推到GC的堆栈,是灰色对象B指向白色C的引用,如果一旦某一个引用消失掉了,会把它放到栈(GC方法运行时数据也是来自栈中),其实还是能找到它的,下回直接扫描他就行了,那样白色就不会漏标。再次做一个快照,然后两个快照进行对比,发现C不是垃圾,那就要对C单独再做一次处理。

对应 G1 的垃圾回收过程中的:最终标记

对用户线程做另外一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录(漏标对象)

(3)incremental update与STAB对比

为什么CMS不用快照,为什么G1不用增量

incremental Update算法关注引用的增加。(A-C的引用),如果增加了就变灰色,需要重新扫描

SATB算法是关注引用的删除(B->C的引用)

G1 如果使用 Incremental Update 算法,因为变成灰色的成员还要重新扫,重新再来一遍,效率太低了。

所以 G1 在处理并发标记的过程比 CMS 效率要高,但是占内存高,这个主要是解决漏标的算法决定的。

三、安全点与安全区域

1、安全点(不会发生引用的变化的代码)

用户线程暂停,GC 线程要开始工作,但是要确保用户线程暂停的这行字节码指令是不会导致引用关系的变化。

所以 JVM 会在字节码指令中,选一些指令,作为“安全点”,比如方法调用、循环跳转、异常跳转等,一般是这些指令才会产生安全点。

为什么它叫安全点,GC 时要暂停业务线程,并不是抢占式中断(立马把业务线程中断)而是主动式中断。主动式中断是设置一个标志,这个标志是中断标志,各业务线程在运行过程中会不停的主动去轮询这个标志,一旦发现中断标志为 True,就会在自己最近的“安全点”上主动中断挂起。

业务线程停止---安全点--->垃圾回收线程开始

业务线程主动式中断,GC开始,STW业务线程, 业务线程轮训标志S(0 OR 1),即GC开始标志,主动去中断线程,跑到最近的安全点挂起。

2、安全区域

为什么需要安全区域?

要是业务线程都不执行(业务线程处于 Sleep 或者是 Blocked 状态),那么程序就没办法进入安全点,对于这种情况,就必须引入安全区域。

安全区域是指能够确保在某一段代码片段之中, 引用关系不会发生变化,因此,在这个区域中任意地方开始垃圾收集都是安全的。我们也可以把安全区城看作被扩展拉伸了的安全点。

当用户线程执行到安全区域里面的代码时,首先会标识自己已经进入了安全区域,这段时间里 JVM 要发起 GC 就不必去管这个线程了。

当线程要离开安全区域时,它要判断 JVM 是否已经完成了GC阶段(根节点枚举,或者其他 GC 中需要暂停用户线程的阶段)

1、如果完成了,那线程就当作没事发生过,继续执行。

2、否则它就必须一直等待, 直到收到可以离开安全区域的信号为止。

四、低延迟的垃圾回收器

1、垃圾回收器的三项指标

传统的垃圾回收器一般情况下内存占用、吞吐量、延迟只能同时满足两个。但是现在的发展,延迟这项的目标越来越重要。所以就有低延迟的垃圾回收器。

2、Eplison(了解即可)

这个垃圾回收器不能进行垃圾回收,是一个“不干活”的垃圾回收器,由 RedHat 推出,它还要负责堆的管理与布局、对象的分配、与解释器的协作、与编译器的协作、与监控子系统协作等职责,主要用于需要剥离垃圾收集器影响的性能测试和压力测试。

3、ZGC(了解即可)

有类似于 G1 的 Region,但是没有分代。

标志性的设计是染色指针 ColoredPointers(这个概念了解即可),染色指针有 4TB 的内存限制,但是效率极高,它是一种将少量额外的信息存储在指针上的技术。

它可以做到几乎整个收集过程全程可并发,短暂的 STW 也只与 GC Roots 大小相关而与堆空间内存大小无关,因此可以实现任何堆空间 STW 的时间小于十毫秒的目标。

JDK11 –ZGC(暂停时间不超过 10 毫秒,且不会随着堆的增加而增加,TB 级别的堆回收)):

有色指针、加载屏障。JDK12 支持并发类卸载,进一步缩短暂停时间 JDK13(计划于 2019 年 9 月)将最大堆大小从 4TB 增加到 16TB

4、Shenandoah(了解即可)

第一款非 Oracle 公司开发的垃圾回收器,有类似于 G1 的 Region,但是没有分代。也用到了染色指针 ColoredPointers。效率没有 ZGC 高,大概几十毫秒的目标。

五、GC 参数和GC 日志详解

1、GC 常用参数

-Xmn -Xms -Xmx –Xss 年轻代 最小堆 最大堆 栈空间

-XX:+UseTLAB 使用 TLAB,默认打开

-XX:+PrintTLAB 打印 TLAB 的使用情况

-XX:TLABSize 设置 TLAB 大小

-XX:+DisableExplicitGC 启用用于禁用对的调用处理的选项 System.gc()

-XX:+PrintGC 查看 GC 基本信息

-XX:+PrintGCDetails 查看 GC 详细信息

-XX:+PrintHeapAtGC 每次一次 GC 后,都打印堆信息

-XX:+PrintGCTimeStamps 启用在每个 GC 上打印时间戳的功能

-XX:+PrintGCApplicationConcurrentTime 打印应用程序时间(低)

-XX:+PrintGCApplicationStoppedTime 打印暂停时长(低)

-XX:+PrintReferenceGC 记录回收了多少种不同引用类型的引用(重要性低)

-verbose:class 类加载详细过程

-XX:+PrintVMOptions 可在程序运行时,打印虚拟机接受到的命令行显示参数

-XX:+PrintFlagsFinal -XX:+PrintFlagsInitial 打印所有的 JVM 参数、查看所有 JVM 参数启动的初始值(必须会用)

-XX:MaxTenuringThreshold 升代年龄,最大值 15, 并行(吞吐量)收集器的默认值为 15,而 CMS 收集器的默认值为 6。

2、Parallel 常用参数

-XX:SurvivorRatio 设置伊甸园空间大小与幸存者空间大小之间的比率。默认情况下,此选项设置为 8

-XX:PreTenureSizeThreshold 大对象到底多大,大于这个值的参数直接在老年代分配

-XX:MaxTenuringThreshold 升代年龄,最大值 15, 并行(吞吐量)收集器的默认值为 15,而 CMS 收集器的默认值为 6。

-XX:+ParallelGCThreads 并行收集器的线程数,同样适用于 CMS,一般设为和 CPU 核数相同

-XX:+UseAdaptiveSizePolicy 自动选择各区大小比例

3、CMS 常用参数

-XX:+UseConcMarkSweepGC 启用 CMS 垃圾回收器

-XX:+ParallelGCThreads 并行收集器的线程数,同样适用于CMS,一般设为和 CPU 核数相同

-XX:CMSInitiatingOccupancyFraction 使用多少比例的老年代后开始 CMS 收集,默认是 68%(近似值),如果频繁发生 SerialOld 卡顿,应该调小,(频繁 CMS 回收)

-XX:+UseCMSCompactAtFullCollection 在 FGC 时进行压缩

-XX:CMSFullGCsBeforeCompaction 多少次 FGC 之后进行压缩

-XX:+CMSClassUnloadingEnabled 使用并发标记扫描(CMS)垃圾收集器时,启用类卸载。默认情况下启用此选项。

-XX:CMSInitiatingPermOccupancyFraction 达到什么比例时进行 Perm 回收,JDK 8 中不推荐使用此选项,不能替代。

-XX:GCTimeRatio 设置 GC 时间占用程序运行时间的百分比(不推荐使用)

-XX:MaxGCPauseMillis 停顿时间,是一个建议时间,GC 会尝试用各种手段达到这个时间,比如减小年轻代

4、G1 常用参数

-XX:+UseG1GC 启用 CMS 垃圾收集器

-XX:MaxGCPauseMillis 设置最大 GC 暂停时间的目标(以毫秒为单位)。这是一个软目标,并且 JVM 将尽最大的努力(G1 会尝试调整 Young 区的块数来)来实

现它。默认情况下,没有最大暂停时间值。

-XX:GCPauseIntervalMillis GC 的间隔时间

-XX:+G1HeapRegionSize 分区大小,建议逐渐增大该值,1 2 4 8 16 32。随着 size 增加,垃圾的存活时间更长,GC 间隔更长,但每次 GC 的时间也会更长

-XX:G1NewSizePercent 新生代最小比例,默认为 5%

-XX:G1MaxNewSizePercent 新生代最大比例,默认为 60%

-XX:GCTimeRatioGC 时间建议比例,G1 会根据这个值调整堆空间

-XX:ConcGCThreads 线程数量

-XX:InitiatingHeapOccupancyPercent 启动 G1 的堆空间占用比例,根据整个堆的占用而触发并发 GC 周期

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/213365.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

回归预测 | MATLAB实现CNN-BiLSTM(卷积双向长短期记忆神经网络

效果一览 基本介绍 提出一种同时考虑时间与空间因素的卷积-双向长短期记忆( CNN-BiLSTM)模型,将具有空间局部特征提取能力的卷积神经网络(CNN)和具有能同时考虑前后方向长时间信息的双向长短期记忆&#xf…

PHP 二维码内容解析、二维码识别

目录 1.首先是一些错误的示例 2.正确示例 3.二维码解析 4.完整示例,含生成 5.代码执行结果 6.参考文档 1.首先是一些错误的示例 本示例使用的是php7.3 通过搜索各种结果逐个尝试以后,得出一个可使用版本 解析错误经历:vendor核心报错 …

springboot 极简案例

安装idea File -> New Project 选择依赖 创建controller文件 输入controller类名 输入代码 运行项目 访问 localhost:8080/hello/boot package com.example.demo;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.…

WordCount 源码解析 Mapper,Reducer,Driver

创建包 com.nefu.mapreduce.wordcount ,开始编写 Mapper , Reducer , Driver 用户编写的程序分成三个部分: Mapper 、 Reducer 和 Driver 。 ( 1 ) Mapper 阶段 ➢ 用户自定义的 Mapper 要继承自己的父…

Java最全面试题专题---1、Java基础知识(3)

IO流 java 中 IO 流分为几种? 按照流的流向分,可以分为输入流和输出流;按照操作单元划分,可以划分为字节流和字符流;按照流的角色划分为节点流和处理流。 Java Io流共涉及40多个类,这些类看上去很杂乱,…

【uC/OS-II】

uC/OS-II 1. uC/OS-II1.1 代码组成1.2 任务基本概念1.3 任务控制块![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/23fe7cd390b94b7eb06a110b10165d22.png)1.4 任务的状态与切换1.5 任务创建的代码 2 任务2.1 系统任务2.2 任务管理相关函数2.3 任务基本属性2.4 uC/…

【Spring 源码】 贯穿 Bean 生命周期的核心类之 AbstractAutowireCapableBeanFactory

🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🌺 仓库主页: Gitee 💫 Github 💫 GitCode 💖 欢迎点赞…

Qt基础-组件的添加、删除或更新

本文介绍如何在Qt中组件的添加、删除或更新。 概述 有时安装完qt后发现当前的组件需要进一步调整,这时就需要进一步操作安装的文件。 QT的组件管理软件并没有在开始菜单或者桌面添加快捷方式(5.9版本),也没有在代码编辑界面设置相关的选项,藏的比较深。 操作步骤 找到…

常见的中间件--消息队列中间件测试点

最近刷题,看到了有问中间件的题目,于是整理了一些中间件的知识,大多是在小破站上的笔记,仅供大家参考~ 主要分为七个部分来分享: 一、常见的中间件 二、什么是队列? 三、常见消息队列MQ的比较 四、队列…

百度APP iOS端包体积50M优化实践(七)编译器优化

一. 前言 百度APP iOS端包体积优化系列文章的前六篇重点介绍了包体积优化整体方案、图片优化、资源优化、代码优化、无用类优化、HEIC图片优化实践和无用方法清理,图片优化是从无用图片、Asset Catalog和HEIC格式三个角度做深度优化;资源优化包括大资源…

大数据技术4:Lambda和Kappa架构区别

前言:在大数据处理领域,两种突出的数据架构已成为处理大量数据的流行选择:Lambda 架构和 Kappa 架构。这些架构为实时处理和批处理提供了强大的技术解决方案,使组织能够从其数据中获得有价值的见解。随着互联网时代来临&#xff0…

金蝶 Apusic 应用服务器任意文件上传漏洞

声明 本文仅用于技术交流,请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。 1. 产品介绍 金蝶 Apusic 是金蝶集团旗下的一款企业级应用服务器&#…

Apollo新版本Beta自动驾驶技术沙龙参会体验有感—百度自动驾驶开源框架

在繁忙的都市生活中,我们时常对未来的科技发展充满了好奇和期待。而近日,我有幸参加了一场引领科技潮流的线下技术沙龙,主题便是探索自动驾驶的魅力——一个让我们身临其境感受创新、了解技术巨擘的机会。 在12月2日我有幸参加了Apollo新版本…

c/c++中一些不常用但有用的知识

1.变长数组 bool fun(int cnt) {unsigned char data[cnt];return true; } 在 C 语言中,变长数组(Variable Length Arrays,VLA)是 C99 标准引入的特性,允许使用变量来定义数组的长度。因此,在 C 版本的代码…

【51单片机系列】74HC595实现对LED点阵的控制

本文是关于LED点阵的使用,使用74HC595模块实现对LED点阵的控制。 文章目录 一、8x8LED点阵的原理1.1 LED点阵显示原理1.2 LED点阵内部结构图1.3 开发板上的LED点阵原理图1.4 74HC595芯片 二、使用74HC595模块实现流水灯效果三、 使用74HC595模块控制LED点阵对角线亮…

插入排序与希尔排序(C语言实现)

1.插入排序 由上面的动图可以知道插入排序的逻辑就是从第一个元素开始往后遍历,如果找到比前一个元素小的(或者大的)就往前排,所以插入排序的每一次遍历都会保证前面的数据是有序的,接下类用代码进行讲解。 我们这里传…

【vSphere | VM】虚拟机自定义规范Ⅲ —— 创建 Linux 虚拟机自定义规范

目录 4. 创建关于Linux系统的虚拟机自定义规范4.1 新建 Linux 虚拟机自定义规范(1)名称和目标操作系统(2)计算机名称(3)时区(4)自定义脚本(5)网络&#xff08…

mybatis 的快速入门以及基于spring boot整合mybatis(一)

MyBatis基础 MyBatis是一款非常优秀的持久层框架,用于简化JDBC的开发 准备工作: 1,创建sprong boot工程,引入mybatis相关依赖2,准备数据库表User,实体类User3, 配置MyBatis(在applic…

C 语言 变量

变量初始值 全局变量:初始值是 0 局部变量:初始值是 随机的 类型限定符 通常不需要显式使用 register 关键字来优化变量的存储和访问。 关键字 _Complex和_Imaginary分别用于表示复数和虚数(二者皆是数学概念) 变量的声明和定义 c…

dell服务器重启后显示器黑屏

1.硬件层面:观察主机的指示灯 (1)指示灯偏黄,硬件存在问题(内存条有静电,拔出后用橡皮擦擦拭;或GPU松动) a.电源指示灯黄,闪烁三下再闪烁一下,扣下主板上的纽…