垃圾收集器与内存分配机制(三)

目录

学习前言

一、低延迟垃圾收集器

1. Shenandoah收集器

二、ZGC

1. 内存布局

2. 更巧妙的并发整理

三、其他垃圾收集器


学习前言

除了之前我们所学习的经典垃圾收集器除外,我们还有一些低延迟垃圾收集等!

之前所学经典垃圾收集器,请参考本篇文章:垃圾收集器与内存分配机制(二)

一、低延迟垃圾收集器

衡量一款垃圾收集器有三项最重要的指标:

  • 内存占用(Footprint)
  • 吞吐量(throughput)
  • 延迟(Latency)

这三者大约是一个不可能三角,一款优秀的收集器通常可以在其中一到两项上做到很好。而随着硬件的发展,这

三者中,延迟的重要性越来越凸显出来。原因有三:一是随着内存越来越大还越来越便宜,我们越来越能容忍收

集器占用多一点的内存;二是硬件性能的增长,比如更快的CPU处理速度,这对软件系统的处理能力是有直接提

升的,它有助于降低收集器运行时对应用程序的影响,换句话说,JVM吞吐量会更高;三,与前两者相反,有些

硬件提升,特别是内存容量的提升,并不会直接降低延迟,相反,它会带来负面效果,更多的内存回收必然使得

回收耗时更长。

因此,在当下,垃圾收集器的主要目标就是低延迟。

对于HotSpot而言,目前有两款转正不久的低延迟垃圾收集器:

Shenandoah与ZGC。它们在低延迟方面与之前梳理过得经典垃圾收集器比较如下:

从上图可以看出垃圾回收器的发展趋势:

  1. 尽量增加并发,以减少STW。G1目标是200ms,但实际只能做到四五百ms上下,Shenandoah目前可以做到几十ms以内,ZGC就牛逼了,10ms以内。
  2. 尽量减少空间碎片,以保证吞吐量。少用标记清除算法,事实上除了CMS也没谁用。

除了Parallel,从CMS到G1,再到Shenandoah与ZGC,都是在想办法并发地完成标记与回收,以达到降低延迟的

目的。

同时为了尽可能保证吞吐量,在回收阶段也尽量使用整理算法而不是清除算法。

继G1之后,Shenandoah与ZGC的目标就是,在尽可能对吞吐量影响不太大的前提下,实现任意堆内存大小下都

可以把垃圾收集的停顿时间限制在十毫秒以内的低延迟。即:大内存,低延迟。

Shenandoah与ZGC在Java15中都已经成为正式特性(但默认GC还是G1),下面简单梳理一下Shenandoah与ZGC

的特点,它们的关键都在于,如何实现并发整理。

1. Shenandoah收集器

Shenandoah收集器在技术上可以认为是G1的下一代继承者。但它不是由Oracle主推发展的收集器,它是由

RedHat公司主推的,属于OpenJDK的特性,而非OralceJDK的特性。它在OpenJDK12中引入成为实验特性,在

OpenJDK15中成为正式特性。

Shenandoah与G1一样,使用基于Region的堆内存布局,有用于巨型对象存储的 Humongous Region ,有基于

回收价值的回收策略,在初始标记、并发标记等阶段的处理思路上高度一致,甚至直接共享了一部分实现代码。

这使得G1的一些改善会同时反映到Shenandoah上,Shenandoah的一些新特性也会出现在G1中。例如G1的收集

担保 Full GC ,以前是单线程的 MSC,就是由于合并了Shenandoah的代码,才变为并行的多线程 MSC 。

Shenandoah相比G1,主要有以下改进:

  1. 回收阶段支持并发整理算法;
  2. 不支持分代收集理论,不再将Region区分为新生代和老年代;
  3. 不使用RSet记忆集,改为全局的连接矩阵,连接矩阵就是一个二维表,RegionN有对象引用ReginM的对

象,就在二维表的N行M列上打钩。

在大的流程上,因为不再基于分代收集理论,Shenandoah并没有所谓YoungGC和OldGC或MixedGC。

它的主要流程类似G1的并发标记周期和混合收集周期:

  • 初始标记:标记与GCRoots直接关联的对象,短暂STW。
  • 并发标记:与G1类似,并发执行,标记可达对象。
  • 重新标记:使用SATB原始快照算法重新标记,并统计出各个Region的回收价值,将最高的Regions组成一个

CSet,短暂STW。

  • 并发清理:将没有任何存活对象的Region直接清空。
  • 并发回收:从这里开始,就是Shenandoah和G1的关键差异,Shenandoah先把回收集里面的存活对象先复

制一份到其他未被使用的Region中,并利用转发指针、CAS与读写屏障等技术来保证并发运行的用户线程能

同时保持对移动对象的访问(※1)。

  • 初始引用更新:并发回收阶段复制对象结束后,需要把堆中所有指向旧对象的引用修正到复制后的新地址,

这个操作称为引用更新。初始引用更新这个阶段实际上并未做具体的更新处理,而是建立一个线程集合的时

间点,确保所有并发回收阶段中的GC线程都已完成分配给它们的对象复制任务而已。初始引用更新时间很短,

会产生一个非常短暂的STW。

  • 并发引用更新:开始并发执行引用更新,找到对象引用链中的引用所在,将旧的引用地址改为新的引用地

址。

  • 最终引用更新:更新GCRoots中的引用。
  • 并发清理:回收CSet中的Regions。

※1 实现并发整理的关键技术:转发指针、CAS与读写屏障

转发指针,Brooks Pointer,Brooks是一个人的名字,转发指针技术由其提出。该技术在原有对象布局结构的最

前面统一增加一个新的引用字段,在正常不处于并发移动的情况下,该引用指向对象自己;当对象被复制,有了一份

新的副本时,只需要修改旧对象上转发指针的引用位置,使其指向新对象,便可将所有对该对象的访问转发到新

的副本上。这样只要旧对象的内存仍然存在,未被清理掉,虚拟机内存中所有通过旧引用地址访问的代码便仍然

可用,都会被自动转发到新对象上继续工作。而当引用地址全部被更新之后,旧对象就不会再被访问到,转发指

针不再由永无之地,随着旧对象一起被释放。

当然,使用转发指针会有线程安全问题。

比如GC线程复制对象和用户线程对旧对象执行写操作这两个动作如果同时发生,就有可能出现线程安全问题。

Shenandoah在这里是采用Compare And SwapCAS技术来保证线程安全的。

CAS是一种乐观锁,比较并替换。

另外,在对象被访问时触发转发指针动作,需要使用读写屏障技术,在对象的各种读写操作(包括读,写,比较,

hash,加锁等等)上做一个拦截,类似AOP。

注意,这里的读写屏障并不是JMM中的内存屏障。

内存屏障类似同步锁,是多线程环境下工作线程与主存之间保证共享变量的线程安全的技术。

事实上,在之前介绍的其他收集器中,已经利用到了写屏障技术,比如CMS与G1中的并发标记等。

Shenandoah不仅要用写屏障,还要用读屏障,这是它之前的性能瓶颈之一,但在Java13中得到了改善,改为使

用Load Reference Barrier,引用访问屏障,只拦截对象中数据类型为引用类型的读写操作,而不去管原生数据

类型等其他非引用字段的读写,这能够省去大量对原生类型、对象比较、对象加锁等场景中设置屏障所带来的消

耗。

目前,Shenandoah在停顿时间上与G1等经典收集器相比有了质的飞跃,已经能够做到几十毫秒;

但一方面还没有达到预期的10ms以内,另一方面却引起了吞吐量的明显下降,尤其是和Parallel Scavenge相

比。

二、ZGC

Z Garbage Collector,简称ZGC。ZGC是Oracle主推的下一代低延迟垃圾收集器,它在Java11中加入JVM作为实

验特性,在Java15中成为正式特性。目前还不是默认GC,但很有可能成为继G1之后的HotSpot默认垃圾回收器。

ZGC虽然目标和Shenandoah一样,都是把停顿时间控制在10ms以内,但它们的思路却完全不一样。就目前而

言,ZGC基本已经做到了,而Shenandoah还需要继续改善。

ZGC收集器是一款基于Region内存布局的,(暂时)不设分代的,使用了读屏障、染色指针和内存多重映射等技术

来实现可并发的标记-整理算法的,以低延迟为首要目标的一款垃圾收集器。其主要特点如下:

  1. 动态的Region布局
  2. 回收阶段支持更巧妙的并发整理

1. 内存布局

ZGC的Region是动态创建和销毁的,且大小不是全部相同的。

在X64平台下,ZGC的Region有大、中、小三个容量:

  • 小型Region,容量固定为2M,用于存放小于256K的小对象。
  • 中型Region,容量固定为32M,用于存放[256K~4M)的对象。
  • 大型Region,容量不固定,但必须是2M的整数倍,用于存放4M及以上的大对象。每个大型Region只会存放

一个大对象,这意味着会有小于中型Region的大型Region,比如最小的大型Region只有4M,就比32M的中

型Region小。大型Region在ZGC中是不会被移动的。

2. 更巧妙的并发整理

ZGC的运行阶段大致如下(初始标记什么的就不写了):

  • 并发标记:对所有Regions做并发的可达性分析,但标记的结果记在引用地址的固定位置上。这个技术叫染色

指针技术(※1)。

  • 并发预备重分配:根据标记结果将所有存活对象所属的Region计入重分配集Relocation Set。
  • 并发重分配:并发地将重分配集中的存活对象复制到空闲Region中,并未重分配集中的每一个Region维护一

个转发表Forward Table,记录旧对象到新对象的转发关系。由于染色指针技术的使用,ZGC仅仅从引用上就

能获知该对象是否在重分配集中(存活对象),通过预置好的读写屏障,如果用户线程并发访问了该对象,就会

被截获并根据转发表转发到复制的新对象上,同时自动修正引用地址到新对象地址,这种自动修改引用地址

的行为被称为自愈。ZGC这种设计的好处是,转发只会发生一次,并发期间用户线程再次访问该对象就没有

转发的损耗了,不像Shenandoah的转发指针技术,在并发期间用户线程每次访问该对象都要转发一下。另外

的好处是,由于染色指针技术,重分配集中的存活对象只要被复制完,就可以立即清空这个Region,只要保

留其对应转发表即可。

  • 并发重映射:修正整个堆中对重分配集中旧对象的所有引用。这个阶段并不是一个迫切要完成的阶段,因为

在ZGC的设立里,引用可以"自愈"。但这么做还是有好处:释放转发表。因此ZGC选择将并发重映射这一步骤

放到下一次GC的并发标记阶段去完成,这样省下了一次遍历引用链的过程。

※1 染色指针技术

染色指针技术Colored Pointer是ZGC的标志性设计。一般收集器在可达性分析标记对象的三色状态时,都是标记

在对象或与对象相关的数据结构上。而染色指针技术是将三色状态直接标记到引用这个"指针",或者说内存地址

上。以64位的linux为例,它支持的内存地址空间去掉保留的高位18位不能使用,还剩下46位。ZGC将这剩下的46

位中的高4位拿出来存储4个标志信息,包括三色状态,对象是否已经被复制,是否只能通过finalize方法访问。

染色指针技术要直接修改操作系统的内存地址,这是需要操作系统和CPU的支持的。

在x86-64平台上,就需要利用到虚拟内存多重映射技术了。

染色指针技术带来的收益:

  1. 一旦重分配集中的某个Region的存活对象全部复制结束后,该Region能够立即清空,马上就可以拿来分配新

对象。这使得ZGC可以在空闲Region极少的极端情况下依然保证能够完成回收。

  1. 大幅减少在对象上设置读写屏障导致的性能损耗。因为可以直接从指针读到三色标记,是否已被复制等信

息。这使得GC对用户线程的性能影响减低,即,减少了ZGC对吞吐量的影响。

  1. 染色指针是一种可以扩展的技术,比如现在不能使用的高位18位,如果开发了这18位,ZGC就不必侵占目前

的46位,从而扩大支持的堆内存容量,也可以记录一些其他的标志信息。

染色指针技术的劣势:

  1. 不支持32位操作系统,因为没有地址空间不够。
  2. 由于把内存地址的高4位拿来做染色指针的存储了,所以导致能够管理的内存不能超过2的42次幂,即4TB。

目前来说,倒是完全够用。大内存的Java应用有上百G就不得了了。与这点限制相比,它能带来的收益要大得

多。

目前ZGC的优势还是很明显的,停顿时间方面,已经做到了10ms以内,而在"弱势"的吞吐量方面,居然也已经基

本追平以吞吐量为目标的Parallel Scavenge。基本上可以认为是完全超越G1的。但ZGC也有需要权衡的地方,

ZGC没有分代,不能针对新生代那种"朝生夕灭"的对象做针对性的优化,这导致ZGC能够承受的内存分配速度不会

太高。即,在一个会连续的高速的大量的分配内存的场景下,ZGC每次收集周期都会产生大量浮动垃圾,当回收

速度跟不上浮动垃圾产生的速度时,堆中的剩余空间会越来越少,最后可能导致收集失败。

目前只能通过加大堆内存的方式缓解这个问题。

其实从CMS到G1,以及Shenandoah都有浮动垃圾的问题。但前两者的分代设计基本保证浮动垃圾不会太多,

Shenandoah其实也有类似 YoungGC 的阶段设计去处理大量的新生对象。

三、其他垃圾收集器

除了以上梳理的7种经典垃圾收集器和两种低延迟垃圾收集器,还有一些其他的GC:

  1. Java11增加了一个叫 Epsilon 的收集器。它的特点就是对内存的管理是只分配,不回收。用途之一是用于需要剥离垃圾收集器影响的性能与压力测试;另外的用途是那些运行负载极小不需要任何回收的小应用,比如Function服务,几秒就执行完的脚本,特点就是跑完就关闭JVM。
  2. Azul的 Pauseless GC,简称 PGC,和 Concurrent Continuously Compacting Collector ,简称 C4。它们大约相当于ZGC的同胞前辈,但它们都是商用VM的GC,早就做到了标记和整理的全程并发。PGC运行在 Azul VM 上,C4运行在 Zing VM 上,且C4支持分代。从技术上讲,PGC、C4、ZGC一脉相承。目前ZGC相当于PGC,由于技术复杂性的原因,还没有支持分代。但未来应该也会考虑做到C4那样支持分代。
  3. OpenJDK现在除了HotSpot虚拟机,还支持OpenJ9虚拟机,它有自己的垃圾收集器如 Scavenger,Concurrent Mark,Incremental Generational 等等,不了解。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu 安装nginx

sudo apt-get update sudo apt-get install nginx sudo nginx -vsudo systemctl status nginx sudo systemctl start nginx sudo systemctl stop nginx sudo systemctl restart nginx#浏览器输入:http://192.168.31.181/#查看文件结构 cd /etc/nginx sudo cp nginx.…

瑞云快图云渲染怎么样?渲染一张图贵吗?

在如今的数字时代,云渲染已经成为了设计师和建筑师们不可或缺的工具。而瑞云快图作为一款备受瞩目的云渲染平台,以其出色的性能和实惠的价格吸引了众多用户。 那么,瑞云快图云渲染究竟怎么样?渲染一张图贵吗?本文将为…

kernel32.dll下载地址:如何安全地恢复系统文件

关于从网络上寻找kernel32.dll的下载地址,这通常不是一个安全的做法,而且可能涉及到多种风险。kernel32.dll是Windows操作系统的核心组件之一,负责内存管理、进程和线程管理以及其他关键系统功能。因为kernel32.dll是系统的基础文件&#xff…

初试PostgreSQL数据库

文章目录 一、PostgreSQL数据库概述1.1 PostgreSQL的历史1.2 PostgreSQL安装1.3 安装PostgreSQL二、PostgreSQL起步2.1 连接数据库2.1.1 SQL Shell2.1.2 执行SQL语句2.2 pgAdmin 42.2.1 打开pgAdmin 42.2.2 查找数据库2.2.3 打开查询工具2.2.4 执行SQL语句三、实战小结文章目录…

使用cmdline-tools安装Android SDK与NDK

1.下载SDK工具: www.android.com 选择下载平台包 同意并下载Command Line Tools 下载中 下载完成后解压 2. 创建android sdk目录并复制sdk工具 创建目录

一文彻底弄懂MySQL的MVCC多版本控制器

InnoDB 的 MVCC(Multi-Version Concurrency Control,多版本并发控制) 是 MySQL 实现高并发事务处理的一种机制。通过 MVCC,InnoDB 可以在高并发环境下支持 事务隔离,并提供 非阻塞的读操作,从而避免锁定所有…

Docker配置网站环境

Mysql 先安装mysql 启动并后台运行:run -d 容器名称:--name 设置端口映射:-p 主机端口:容器端口 环境变量:-e 最后指定镜像名称 sudo docker run -d \--name mysql\-p 3306:3306\-e MYSQL_ROOT_PASSWORD123456\…

开发工具(上)

前面我们在Linux部分了解文件权限,和基本指令的内容,但对于开发工具还是没有很多的接触,现在这一篇就是主要讲基础的工具;如yum,yum源,包管理器等等; Linux中的安装软件: 源码安装 …

落地 ZeroETL 轻量化架构,ByteHouse 推出“四个一体化”策略

在数字化转型的浪潮中,数据仓库作为企业的核心数据资产,其重要性日益凸显。随着业务范围扩大,企业也会使用不同的数据仓库来管理、维护相关数据。研发人员需要花费大量时间和精力,从中导出数据,然后进行手动整理、转换…

一文1800字从0到1浅谈web性能测试!

什么是性能测试? web性能应该注意些什么? 性能测试,简而言之就是模仿用户对一个系统进行大批量的操作,得出系统各项性能指标和性能瓶颈,并从中发现存在的问题,通过多方协助调优的过程。而web端的性能测试…

PYQT5 简单项目实践

在VSCode编辑器我们通过引入pyqt5,用QTdesigner 实现拖拽实现图形化界面 下面我们实现一个简单项目实践一下吧 效果图: 用法:Python编写逻辑,用pyqt实现界面显示。 功能: 第一行把处理的数据文件拖拽到文本框中第二…

017_基于python+django美术馆预约系统2024_802l04c5

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍:CodeMentor毕业设计领航者、全网关注者30W群落,InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者,博客领航之星、开发者头条/腾讯云/AW…

GPIO口的学习

推挽输出 用它去控制一个mos管,当输出高电平时电流这样流出去,给外面的这颗mos管的栅极充电,所以这个过程称为推把电流推出去 然后当IO口输出低电平时电流这样流进来,给外面的这颗mos管的栅极放电,那这就是挽,把电流挽回来,所以所…

Android Framework AMS(06)startActivity分析-3(补充:onPause和onStop相关流程解读)

该系列文章总纲链接:专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明: 说明:本章节主要解读AMS通过startActivity启动Activity的整个流程的补充,更新了startActivity流程分析部分。 一般来说,有Activ…

IT监控平台可视化:3D机房与设备监控的革新实践

在信息化高速发展的今天,IT运维行业面临着前所未有的挑战。随着数据中心规模的不断扩大和设备复杂度的日益提升,如何高效、准确地监控和管理这些设备,成为了运维团队亟待解决的问题。IT监控平台的可视化功能,尤其是3D机房与设备监…

从零开始学PHP之输出语句变量常量

一、 输出方式 在 PHP 中输出方式: echo,print,print_r,var_dump 1、echo和print为php的输出语句 2、var_dump,print_r为php的输出函数 (这里不做介绍)echo 和 print 区别 1、echo - 可以输出…

CSS3 提示框带边角popover

CSS3 提示框带边角popover。因为需要绝对定位子元素&#xff08;这里就是伪元素&#xff09;&#xff0c;所以需要将其设置为相对对位 <!DOCTYPE html> <html> <head> <title>test1.html</title> <meta name"keywords" con…

uniapp_微信小程序_echarts_动态折线图

##uniapp_微信小程序_echarts_动态折线图 用来总结和学习&#xff0c;便于自己查找 文章目录 一、为什么使用echarts折线图?          1.1 动态折线图echarts效果&#xff1f; 二、怎么导入echarts折线图&#xff1f;          2.…

spring boot 3.3.4 网关(gateway) 集成knife4j 4.4.0

spring boot版本 3.3.4&#xff0c;jdk 22&#xff0c; springcloud 2023.0.3 官方参考链接 Spring Cloud Gateway网关聚合 | Knife4j (xiaominfo.com) springboot版本信息 <properties> <java.version>22</java.version> <spring-cloud.version>2023…

LSTM反向传播及公式推导

先回顾一下正向传播的公式: 化简一下: 反向传播从下到上逐步求偏导: 对zt求偏导(预测值和标签值相减): zt对未知数wt,ht,bt分别求偏导: ht对ot,Ct求偏导: ot对Net0求偏导: Net0对w0,b0求偏导: .... 总体的思路就是那个公式从下到上逐步对未知数求偏导: 下面是总体的流程…