JVM:如果是你,你如何解决跨代引用的问题?(记忆集和卡集)

这部分内容主要是为了稍后介绍各款垃圾收集器时做前置知识铺垫,如果对这部分内容感到枯燥或者疑惑,可以先放下看,等后续遇到要使用它们的实际场景、实际问题时再结合问题,再回来阅读和理解。

记忆集和卡集

前面在分代收集理论那一节稍微讲到对象不是孤立的,对象之间存在跨代引用。如果还是不大明白,看我下面这个例子:老年代引用年轻代

public class ClassRoomLocalCache {// 静态变量 map,以及 map 中引用的 ClassRoom 类型变量大概熬过默认的 15 次垃圾收集,都会晋升到老年代private static final Map<String,ClassRoom> map = new ConcurrentHashMap<>();public static void addStudent(String classRoomId) {// ......// 运行时,新初始化了一个对象 Student ,对象实例假设在年轻代分配内存// 老年代引用年轻代map.get(classRoomId).getUsers().add(new Student("127", "李华", 22));}@Getterprivate static class ClassRoom {private String id;private String name;private Integer num;private List<Student> users;}@AllArgsConstructorprivate static class Student {private String id;private String name;private Integer age;}}

再回一下前面提到的经验法则三,为什么说跨代引用相对于同代引用来说仅占极少数?

因为存在互相引用关系的两个对象,是应该倾向于同时生存或者同时消亡的。例如上面程序中的这个例子(稍微结合例子解释下)

举个例子,如果某个新生代对象存在跨代引用,由于老年代对象难以消亡,该引用会使得新生代对象在收集时同样得以存活,进而在年龄增长之后晋升到老年代中,这时跨代引用也随即被消除了。 

其实上面说的只是一个经验法则或者说是理论,实际上并没有解决当需要在年轻代gc 时因可能存在跨在引用,为了找出该区域中的存活对象,不得不在固定的GC Roots之外,再额外遍历整个老年代中所有对象来确保可达性分析结果的正确性

事实上并不只是新生代、老年代之间才有跨代引用的问题,所有涉及部分区域收集(Partial GC)行为的垃圾收集器(G1、ZGC)都会面临相同的问题。

可以想一下,如果是你,你会怎么设计解决这个问题?

由于跨代引用占极少数,我想最简单的实现的就是维护一个对象数组,每当有老年代对象引用年轻代对象就把老年代对象存储到这个数组中,然后在年轻代收集时,把这个数组的对象一并加入到gc roots 中去进行扫描。

实际上,JVM 的设计者的思路也大概是这样,就是在收集区域(可以理是新生代)开辟一块小内存维护一个数据结构,这个抽象数据结构用于记录从非收集区域指向收集区域的指针集合,他们称为记忆集。

然而JVM 设计者并没有直接使用如上最简单的实现方案。这种记录全部含跨代引用对象的实现方案,无论是空间占用还是维护成本都相当高昂。而在垃圾收集的场景中,收集器只需要通过记忆集判断出某一块非收集区域是否存在有指向了收集区域的指针就可以了,并不需要了解这些跨代指针的全部细节。那设计者在实现记忆集的时候,他们选择更为粗犷的记录粒度来节省记忆集的存储和维护成本,也就是卡精度的实现方案。

对象精度:每个记录精确到一个对象,该对象里有字段含有跨代指针。 
卡精度:每个记录精确到一块内存区域,该区域内有对象含有跨代指针。

卡精度”所指的是用一种称为“卡表”(Card Table)的方式去实现记忆集,这也是目前最常用的一种记忆集实现形式,一些资料中甚至直接把它和记忆集混为一谈。前面定义中提到记忆集其实是一种“抽象”的数据结构,抽象的意思是只定义了记忆集的行为意图,并没有定义其行为的具体实现。卡表就是记忆集的一种具体实现,它定义了记忆集的记录精度、与堆内存的映射关系等。 (可以对比map 和HashMap)

卡表最简单的形式可以只是一个字节数组,而HotSpot虚拟机确实也是这样做的。以下这行代码是HotSpot默认的卡表标记逻辑:

CARD_TABLE [this address >> 9] = 0;

字节数组CARD_TABLE的每一个元素都对应着其标识的内存区域中一块特定大小的内存块,这个内存块被称作“卡页”(Card Page)。一般来说,卡页大小都是以2的N次幂的字节数,通过上面代码可以看出HotSpot中使用的卡页是2的9次幂,即512字节

img

一个卡页的内存中通常包含不止一个对象,只要卡页内有一个(或更多)对象的字段存在着跨代指针,那就将对应卡表的数组元素的值标识为1,称为这个元素变脏(Dirty),没有则标识为0。在垃圾收集发生时,只要筛选出卡表中变脏的元素,就能轻易得出哪些卡页内存块中包含跨代指针,把它们加入GC Roots中一并扫描。

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

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

相关文章

【Java 进阶篇】JQuery DOM操作:舞动网页的属性魔法

在前端的舞台上&#xff0c;属性操作是我们与HTML元素进行互动的关键步骤之一。而JQuery&#xff0c;这位前端开发的巫师&#xff0c;通过简洁而强大的语法&#xff0c;为我们提供了便捷的属性操作工具。在这篇博客中&#xff0c;我们将深入研究JQuery DOM操作中的属性操作&…

FPGA与STM32_FSMC总线通信实验

FPGA与STM32_FSMC总线通信实验 内部存储器IP核的参数设置创建IP核FPGA代码STM32标准库的程序 STM32F407 上自带 FSMC 控制器&#xff0c;通过 FSMC 总线的地址复用模式实现STM32 与 FPGA 之间的通信&#xff0c;FPGA 内部建立 RAM 块&#xff0c;FPGA 桥接 STM32 和 RAM 块&…

【算法 | 模拟No.5】leetcode 74. 搜索二维矩阵

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

抢抓泛娱乐社交出海新风口!Flat Ads深圳沙龙活动引爆海外市场

随着全球化进程的加速&#xff0c;中国的应用类APP不断走向国际市场。作为产品和服务的提供者&#xff0c;中国开发者围绕社交泛娱乐创新&#xff0c;开启直播出海、短视频出海、游戏社交出海、1V1 视频出海、音频社交出海等出海热潮。“社交、泛娱乐”融合成为行业主流发展趋势…

Go的优雅退出

Go优雅退出/停机以前主要通过signal来实现&#xff0c;当然现在也是通过signal来实现&#xff0c;只是从go 1.16开始&#xff0c;新增了更加友好的API: func NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc) 该…

DevChat:开发者专属的基于IDE插件化编程协助工具

DevChat&#xff1a;开发者专属的基于IDE插件化编程协助工具 一、DevChat 的介绍1.1 DevChat 简介1.2 DevChat 优势 二、DevChat 在 VSCode 上的使用2.1 安装 DevChat2.2 注册 DevChat2.3 使用 DevChat 三、DevChat 的实战四、总结 一、DevChat 的介绍 在AI浪潮的席卷下&#x…

Linux每日智囊

每日分享三个Linux命令,悄悄培养读者的Linux技能。 ls 作用 显示目录信息 语法 ls [选项] 文件 参数: -a:显示所有文件,包含以 . 开头的隐藏文件以及特殊目录-A:显示所有文件,包含以 . 开头的隐藏文件,但不显示特殊文件 . 和 …-l:使用长格式显示当前目录下文件的详…

STM32——NVIC中断优先级管理分析

文章目录 前言一、中断如何响应&#xff1f;NVIC如何分配优先级&#xff1f;二、NVIC中断优先级管理详解三、问题汇总 前言 个人认为本篇文章是我作总结的最好的一篇&#xff0c;用自己的话总结出来清晰易懂&#xff0c;给小白看也能一眼明了&#xff0c;这就是写博客的意义吧…

家庭安全计划 挑战赛| 溺水预防

溺水预防 从了解到行动 家庭安全计划 | 少年急救官 地震避险逃生该怎么做&#xff1f; 起火了该如何应对&#xff1f; 哪些行为容易导致溺水&#xff1f; 家庭风险隐患有哪些&#xff1f; 家庭逃生演练四步骤你会吗&#xff1f; 国际救助儿童会&#xff08;英国&#xff…

3d max软件中的缓存垃圾该如何清理?

使用3d max建模到渲染操作&#xff0c;来回对效果图调整的次数过多时&#xff0c;就会出现一下看不到的垃圾缓存&#xff0c;影响保存的速度&#xff0c;影响效率&#xff01; 对于这类的3d垃圾清理的有什么高效方法呢&#xff1f; 3dmax垃圾清理的常规操作如下&#xff1a; 1、…

Pytest插件

官方文档&#xff1a;API Reference — pytest documentation BaseReport 定义Case结果输出 >>> from _pytest.reports import TestReport >>> test TestReport(1,1,1,pass,,running) >>> print(dir(test)) [__annotations__, __class__, __delatt…

【03】Istio Gateway示例配置

3.1 开放kiali至集群外部 首先将istio-inressateway暴露集群外部; 在node02的ens33网卡上面有多余的ip地址&#xff0c;将该地址绑定在igressgateway的svc 上面。 kubectl edit svc istio-ingressgateway -n istio-system定义kiali的ingress gateway的资源配置清单 apiVersion:…

【广州华锐互动】楼宇智能化VR虚拟教学系统

在如今的技术时代&#xff0c;教育行业正在逐步引入各种创新方法以提升教学质量。VR公司广州华锐互动开发的楼宇智能化VR虚拟教学系统就是其中的一种&#xff0c;它利用虚拟现实(VR)技术&#xff0c;为学生提供一种全新的、沉浸式的学习体验。 楼宇智能化VR虚拟教学系统涵盖综合…

【Spring Boot 源码学习】初识 SpringApplication

Spring Boot 源码学习系列 初识 SpringApplication 引言往期内容主要内容1. Spring Boot 应用程序的启动2. SpringApplication 的实例化2.1 构造方法参数2.2 Web 应用类型推断2.3 加载 BootstrapRegistryInitializer2.4 加载 ApplicationContextInitializer2.5 加载 Applicatio…

Word转PDF简单示例,分别在windows和centos中完成转换

概述 本篇博客以简单的示例代码分别在Windows和Linux环境下完成Word转PDF的文档转换。 文章提供SpringBoot Vue3的示例代码。 文章为什么要分为Windows和Linux环境&#xff1f; 因为在如下提供的Windows后端示例代码中使用documents4j库做转换&#xff0c;此库需要调用命令行…

python的re正则表达式

华子目录 什么是正则表达式元字符字符集字符集与元字符的综合使用 数量规则指定匹配次数边界处理分组匹配贪婪匹配非贪婪匹配re.S转义字符re.search()re.sub()实例常见的匹配模式 什么是正则表达式 正则表达式是一个特殊的字符序列&#xff0c;它能帮助你方便的检查一个字符串…

macOS Big Sur(macos11版本)

macOS Big Sur是苹果推出的最新操作系统&#xff0c;具有以下特点&#xff1a; 全新的设计风格&#xff1a;Big Sur采用了全新的设计语言&#xff0c;包括更加圆润的窗口和控件、更加鲜明的色彩和更加简洁的界面。这种设计风格使得操作系统更加美观和易用。强大的性能表现&…

基于RK3399的室内健身魔镜方案

I 方案背景 一、健身魔镜的兴起 2020年疫情席卷全球&#xff0c;宅家是防疫的措施之一&#xff0c;因而宅家运动火爆&#xff0c;随之而来的宅家运动器材也风靡起来&#xff0c;其中包含既有颜值又具有多种功能的健身魔镜。 Ⅱ 方案介绍 一、健身魔镜的方案介绍 …

windows安装nginx

一、下载安装Nginx 1、官网下载地址&#xff1a;nginx: download 2、下载教程&#xff1a;选择最新的Stable version&#xff08;稳定版本&#xff09;下载到本地 3、下载完成后&#xff0c;解压放入本地非中文的文件夹中&#xff1a; 4、启动nginx&#xff1a;切勿直接双击n…

php的api接口token简单实现

<?php // 生成 Token function generateToken() {$token bin2hex(random_bytes(16)); // 使用随机字节生成 tokenreturn $token; } // 存储 Token&#xff08;这里使用一个全局变量来模拟存储&#xff09; $tokens []; // 验证 Token function validateToken($token) {gl…