ZGC收集器


欢迎来到我的博客:TWind的博客

我的CSDN::Thanwind-CSDN博客

我的掘金:Thanwinde 的个人主页


0.前言

ZGC收集器完全可以说是Java收集器的一个跨时代的收集器,他真正意义上实现了停顿时间在10ms以内并且几乎全时段都是并发的

而且其性能比之前的所有的收集器都更加优越,但初代由于没有分代机制,导致了其不能承受太高的新建对象的速率

但这些在JDK21中被解决,分代ZGC具有更快的速度以及更低的停顿成为了当之无愧的面向延迟的收集器之王

但值得的一提的是,这并不意为着ZGC是所有情况下的最优解,如你所见,ZGC是一个面向延迟的收集器,它实现了在把延迟降到极致的情况下保持不错的吞吐量,而且和ShenandoahGC一样是针对于超大堆(几百G更高的这种),每个场景都有自己适合的收集器(G1全能的含金量还在上升)

尽管它因为没有分代设计而导致可能无法适应高内存分配速度的场景,但仍然瑕不掩瑜,而且在JDK21, Generational ZGC 横空出世,完美解决了这个问题


ZGC收集器

ZGC(Z Garbage Collector),出现于JDK11,主打低延迟,高性能,能控制停顿时间在10ms以内,并实现了基本全程并发

ZGC采用了类似G1的Region的内存分区,参考

在这里插入图片描述

但抛弃了分代理论,这带来了优劣:好处是不用像G1那样维护庞大且复杂的卡表,坏处是无法享受分区带来的高效率清理那些“浮动的”对象

为什么抛弃,并不是分代理论不好,而是过于复杂暂时无法实现(在JDK21实现)

这导致了ZGC不能应对高速率创建新对象的场景:如果是分代的话,这些会被划到新生代针对性处理,而ZGC只会全局扫描一起处理

这就可能导致在清理期间内存又被撑满,导致不得不全局停顿来清理

但即便如此,ZGC仍然瑕不掩瑜:它低到10ms的延迟,不低的吞吐量非常适合大流量注重延迟的业务,比如:新一代垃圾回收器ZGC的探索与实践 - 美团技术团队

现在,让我们来具体了解一下ZGC

内存布局

ZGC采用了类似于G1的内存布局,将内存分为一个个Region,但是区别在于:

  • 没有新生代,老年代等

  • 没有卡表(没有跨代)

  • 具体大小固定:

  • 小型区/页(Small):固定大小为2MB,用于分配小于256KB的对象。

    中型区/页(Medium):固定大小为32MB,用于分配>=256KB ~ <=4MB的对象。

    大型区/页(Large):没有固定大小,容量可以动态变化,但是大小必须为2MB的整数倍,专门用于存放>4MB的巨型对象。但每个Large只能存放一个对象,无论你这个对象多大。而且Large是不会重分配(后面解释)

    除了大型区,其他两个区都可能会容纳不止一个对象,且不一定装满:剩下的空间会被浪费掉

ZGC抛弃了分代换来了更简单的内存布局,但是代价就是无法应对高速产生的对象,逻辑分区是这个问题的最优解,可惜ZGC没有实现,但可喜的是,jdk21 时ZGC补全了这最后一块拼图

染色指针

染色指针是什么?可以类比java的对象头:对象头存储了一个对象的基本信息,譬如哈希值,偏向锁等等,这样就可以在不实际访问这个对象的前提下得到这个对象的信息。

在GC中,确定回收哪些对象时要用到三色标记,在ZGC之前都是要用其他的数据结构来维护这个对象的状态:已遍历(黑),未遍历(白),未完全遍历(灰)这增加了不少了负担。而染色指针将这个信息直接设法集成到了这个对象的指针当中:省去了查表的操作

具体是:
在这里插入图片描述

对于64位的Linux系统来说,一个指针有64位,却只会用到46位来寻址:46位已然达到了64TB的大小,ZGC就从中提取出了四位用来mark,即使这样,剩下的42位也有4TB:

  • 第一位Finalizable,用来标志这个对象是否是用finaliza,这个功能目前已然废弃
  • 第二位Remapped,意为重映射,可以简单理解为是用来标志这个对象是否是未活跃:象征着不活跃,会被回收
  • 二三位M1和M0,都是用来标记活跃的,区别在于两个只使用一个,另外一个表示上一次GC的结果,举个例子,假如对象A第一轮被标记了M0,第二轮时如果没有被标记,那他还是M0,但这时判断的是M1,就会把对象A回收,如果都是一个M标记的话,就无法处理这种情况

但这会有一个问题:需要其他的方法来处理指针,让其能够正确寻址

一般来说,采用了染色指针会导致内存看上去为原来的三倍

为什么?因为0 1 0 0 + 42位寻址指针,0 0 1 0 + 42位寻址指针 , 0 0 0 1 + 42位寻址指针指向的是同一个地址

其它的内存软件不会去额外的解析,就会看成三个地址

这意味着JVM必须要对这个地址进行特殊的解析才能正常使用

这样子的代价除了减少了可用内存,还有不能采用指针压缩:正常情况下,64位的指针会被压缩到32位以节省一半的空间

但影响并不大:当内存超过4G本身就会禁用指针压缩,all in all,染色指针非常有用

具体流程

让我们再具体的分析:
在这里插入图片描述

首先,第一阶段:

并发标记

这里和其他的收集器最开始的行为一样:遍历所有对象来找到GC root,这里会触发STW,同时,如果不是第一次GC,这里会顺便更新引用

一开始,所有的对象都是Remapped状态,随着被标记会变成M0,并且会维护一个的 RSet(回收集),会记录下要回收的Region,到时候就会把这里面存活的对象移走(如果有)然后回收掉原本的区域

并发预备重分配

这里是并发的,具体来说,这里会扫描整个内存区域以看那些Reign要回收:像G1一样,会去回收最有价值的Region:比如一个全是待回收的对象的Region显然是最有价值的

对于这时新建的对象,会默认被标成Remapped

并且对于类卸载以及弱引用也是在这个阶段处理的

与G1不同点就出来了:用扫描范围换取了维护卡表的负担

并发重分配

这里做的主要就是把并发标记的回收集中的Reigon回收,听上去简单,但做着可不见得简单,具体来说:

会把要留下的对象复制到新的Regio中,同时会维护一个转发表来记录对象的老地址和新地址

如果此时有线程来访问这个老地址,会被JVM的内存屏障捕获,查看其指针,如果是M0(M1),也就是存活对象,就会被查转发表转发到他的新地址,并把这个指针修改成新地址,这被称之为指针的“自愈”,而且这种比较慢的转发只会发生一次,因为以后的访问都会被修正,这个做法比起Shenandoah的转发指针大幅降低了负载且减少了屏障的使用

如果这时候用户线程新建了对象,也是Remapped状态

并发重映射

严格来说,这个阶段是和并发标记重合的,因为这个阶段会去把转发表里面那些还没有“自愈”的引用修复

这个行为不是很迫切,因为如果其他线程随时访问都能正常访问到新的地址

目的是在于释放掉这个转发表并且避免再访问老地址会变慢一次的缺陷

因此,ZGC将其合并到了最开始的并发标记阶段之中:反正都要遍历所有的对象,随便修复了

优势点

不难看出,ZGC是基于标记-整理的,一定程度上牺牲了清理效率(虽然是被迫的)而带来了极短的停顿时间

它在中负荷的场景中性能极其优异,但是由于并没有分代策略,导致其无法应付大量对象快速创建的情景,可能会发生全局停顿导致极大的延时

但它仍然是卓越的,新颖的,而更令人兴奋的是,在JDK21, Generational ZGC 横空出世。

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

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

相关文章

隧道技术篇2frp代理nps代理shisel代理

FRP代理 1.实现湖北内网控制北京的内网C2上线 2.实现湖北内网探针北京内网 信息收集 &#xff08;socks建立和端口映射&#xff09; 1.连接47.98.210.85 7000端口服务端 2.尝试将服务端的6666转到127.0.0.1 5555采用tcp协议&#xff0c;备注名proxies serverAddr"47.98…

[Python 基础课程]PyCharm 的安装

Python 的编辑器目前主流的有 PyCharm 和 Vscode。 PyCharm 是 Python 目前最主流、最常用、最推荐的 Python 编辑器。 https://www.jetbrains.com/pycharm/ PyCharm 有社区版和专业版&#xff0c;可以根据自己的需要下载对应的版本。社区版是收费的&#xff0c;对于初学者或…

Spread Ribbon 工具栏控件:在WinForms中高效编辑Spread工作簿

引言 在数据密集型应用中&#xff0c;电子表格功能是提升用户体验的关键要素。GrapeCity Spread.NET V17 推出的独立 Ribbon工具栏控件&#xff0c;为WinForms开发者提供了与Excel高度一致的UI交互体验。通过集成此控件&#xff0c;用户可直观地进行数据编辑、格式调整等操作&…

leedcode:找到字符串中所有字母异位词

问题&#xff1a;给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 package com.text;import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;…

华为云Flexus+DeepSeek征文|基于华为云 Flexus Dify平台开发AI Agent的详细流程

目录 一、Dify 应用开发平台 1.1 什么是 Dify&#xff1f; 1.2 Dify 平台优势 二、构建 AI Agent 2.1 创建智能客服助手 2.2 配置 LLM组件 三、访问智能应用 3.1 应用发布 3.2 智能对话 四、API 调用智能客服助手 4.1 配置 API 访问接口 4.2 调用智能客服助手API …

【知识图谱构建系列7】:结果评价(1)

文章目录 前言前情提要三元组提取结果评价脚本代码分析几分钟后前言 翻了一下记录,发现咱的知识图谱构建已经接近10天没有搞了。时间也是过得真快啊。但这毕竟是咱未来产生论文的主要阵地,所以得赶紧把节奏给拾起来哈~ 前情提要 我们已经可以在mistral模型的基础上,跑通提…

BT下载工具 qBittorrent v5.1.1.10,便携无广告,BT下载速度翻倍

[软件名称]: BT下载工具 qBittorrent v5.1.1.10 [软件大小]: 15.9 MB [下载通道]: 夸克盘 | 迅雷盘 软件介绍 &#x1f525;《qBittorrent增强版》v5.1.1.10便携版&#xff5c;BT下载神器&#xff0c;速度与隐私兼得&#x1f310; ✨ 核心优势&#xff1a; ✅ 无视版权限制…

裂变与重构:2025年大模型生态全景透视及未来趋势研判

1. 2025上半年&#xff1a;大模型生态的裂变时刻 1.1 技术范式革命&#xff1a;从生成到推理的跨越 2025年1月DeepSeek的横空出世&#xff0c;标志着大模型正式进入"推理时代"。这款国产模型在发布首周即突破1亿用户量级&#xff0c;其核心突破在于将传统生成能力升…

【docker】如何正确拉取langgraph-api

加这些配置都没用 # 设置代理环境变量 export HTTP_PROXY=http://127.0.0.1:7890 export HTTPS_PROXY=http://127.0.0.1:7890 # 设置更长的超时时间 export DOCKER_CLIENT_TIMEOUT=

PIXHAWK(ardupilot4.52)上传航点的bug

起因是查看飞控日志时发现地面站上传的平行航线&#xff0c;在日志看到航线却并不是平行的。 然后对比了一下地面站上传的航点信息跟飞控读取到的航点信息 发现经纬度只有前几位能够对应上&#xff0c;后几位都对应不上&#xff0c;两个点之间相差了50公分。地面站工程师认为地…

车载ECU刷写文件格式汇总详解

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 做到欲望极简&#xff0c;了解自己的真实欲望&#xff0c;不受外在潮流的影响&#xff0c;不盲从&#x…

Redis核心知识详解:从全局命令到高级数据结构

一、Redis全局命令详解 1.1 键查看与管理 dbsize&#xff1a;高效获取键总数&#xff08;O(1)操作&#xff09; 127.0.0.1:6379> dbsize (integer) 8 keys&#xff1a;生产环境避免使用&#xff08;O(n)操作&#xff09; # 查找user开头的键&#xff08;不推荐生产使用…

【网络】Linux 内核优化实战 - net.ipv4.tcp_mem

目录 参数结构与含义与缓冲区大小参数的区别内存管理机制详解1. 内存使用状态与触发逻辑2. 与其他参数的协同关系 典型调整场景与配置示例场景 1&#xff1a;高并发低带宽服务&#xff08;如 API 网关&#xff0c;数万连接但单连接流量小&#xff09;场景 2&#xff1a;高带宽低…

插入排序的简单介绍

今天给大家简单介绍一下插入排序。 插入排序&#xff0c;其基本思想是将未排序的数据逐步插入到已排序序列中的合适位置&#xff0c;从而使整个序列逐渐有序。 下面我们看一个排序的过程&#xff08;升序&#xff09;&#xff0c;给定一个int类型的数组&#xff0c;利用插入排…

docker搭建minio和python使用minio

1 准备工作 1.创建目录 [rootk8s-storage tmp]# mkdir -pv minio/{data,conf} mkdir: created directory ‘minio’ mkdir: created directory ‘minio/data’ mkdir: created directory ‘minio/conf’[rootk8s-storage minio]# chmod 777 -R *2.生成https证书 openssl req…

开源代码修复新标杆——月之暗面最新开源编程模型Kimi-Dev-72B本地部署教程,自博弈修复 Bug

一、介绍 Kimi-Dev-72B是由月之暗面&#xff08;Moonshot AI&#xff09;最新开源的AI编程模型&#xff0c;专为软件工程任务设计&#xff0c;并登顶 SWE-bench Verified 基准测试榜首&#xff0c;超越 DeepSeek-R1 等模型&#xff0c;成为当前开源代码模型的 SOTA&#xff1a…

微服务架构之基本设计原则

作为系统架构师&#xff0c;在进行架构设计时需要遵循一系列经过实践验证的核心原则&#xff0c;这些原则贯穿于需求分析、模块划分、技术选型和系统演进的全流程。以下从核心设计原则、架构特性原则、工程实践原则三个维度&#xff0c;结合具体案例展开说明&#xff1a; 一、…

Wpf布局之WrapPanel面板!

文章目录 前言一、引言二、使用步骤 前言 Wpf布局之WrapPanel面板&#xff01; 一、引言 WrapPanel面板以一次一行或一列的方式布置控件&#xff01; 二、使用步骤 WrapPanel面板Orientation属性默认是"Horizontal"&#xff0c;将控件从左向右进行排列&#xff…

QEMU运行RISCV版Ubuntu

宿主机为ubuntu20.04&#xff0c;推荐ubuntu 20.04 risc-v版&#xff0c; 宿主机为ubuntu24.04&#xff0c;推荐ubuntu 24.04 risc-v版&#xff0c; 安装ubuntu 24.04 risc-v基本步骤&#xff1a; 1&#xff0c; sudo apt update sudo apt install opensbi qemu-system-misc…

【LeetCode 热题 100】239. 滑动窗口最大值——(解法一)滑动窗口+暴力解

Problem: 239. 滑动窗口最大值 题目&#xff1a;给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值 。 文章目录 整体思路完整代码时空…