当前位置: 首页 > news >正文

HotSpot的算法细节

可达性分析算法

以一系列“GC Roots”根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”(Reference Chain),如果某个对象到GC Roots间没有任何引用链相连, 或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的。

从GC Roots开始向下进行引用搜索,如果某对象和任何GC Root没有关联,则认为该对象不再被使用。

GC Roots

  • 虚拟机栈中引用的对象,对应虚拟机方法栈中当前执行的方法所使用的参数,局部变量,临时变量等。
  • 方法区中:类的静态变量,常量
  • 本地方法栈中引用的对象

记忆集与卡表

记忆集是一种用于记录从非收集区域指向收集区域的指针集合的抽象数据结构。

卡表:是记忆集的一种实现形式,采用的是“卡精度”的方式实现记忆集。卡精度指精确到一块内存区域(该内存区域又称为“卡页”),这个区域内有跨代指针的话,就将其标识出来(实际是使用的0/1标识);

在进行GCROOTS扫描时,同时再去筛选卡表中变脏的元素(扫描指定的内存区域块),可以快速定位到关联区域,将跨区引用的对象一起加入GCROOTS扫描。

写屏障

写屏障主要解决的是卡表元素的维护更新,即处理卡表变脏的问题。

何时变脏:其他分代区域有对象引用了该区域对象时,其对应的卡表元素则变脏。

写屏障的处理类似于一个AOP切面,即在本区对象被引用时,添加了Around环绕通知,可在引用赋值前后添加写前屏障和写后屏障。通常虚拟机在写后屏障中增加维护卡表的操作。

卡表在高并发场景下还存在伪共享的问题,由于64个卡表共享一个缓存行,当多个线程更新同一缓存行数据时,会出现并发更新影响性能的情况。

同时虚拟机提供-XX:+UseCondCardMark参数配置,开启该参数则会预先检查该卡表是否已变脏,再行更新的策略。对未变脏的进行更新,已经变脏的卡表不再更新。开启该参数增加异常额外判断的开销,但可以避免伪共享的问题

SATB(snapshot at the beginning)原始快照

沿着GCRoots进行并发扫描时,通常用户线程也在并发执行。这时会面临着已经被垃圾收集器扫描的对象图被用户线程更改的情况。

情况一:某些对象被用户线程断开了引用,其实该对象已经成为垃圾,现在仍被垃圾收集器标识为存活

情况二:某些被垃圾收集器标识为垃圾的对象被用户线程重新引用,导致存活对象被垃圾收集器回收了

综合以上两种情况可知,情况一其实可以容忍,只是程序产生了一些浮动垃圾,待下一次垃圾收集时可以一并回收。情况二把原本存活的对象标记为了死亡,则会造成程序的致命错误。

关于情况二即并发扫描时的对象消失问题,不同的垃圾收集器的解决办法不同。CMS中使用增量更新的方式,G1和shenandoah采用原始快照的方式。

CMS使用增量更新的方式:

当有黑色对象插入指向白色对象的引用时,就将这个引用关系记录下来。在并发扫描结束后(最终标记),以这些黑色对象为根再次进行扫描一次。

垃圾收集器扫描完成的对象引用了一个未被扫描过(新创建或已断开引用)的对象,会将该引用关系记录下来,在最终标记阶段再以该新创建的对象为根,再次进行扫描一次。

G1和shenandoah的原始快照方式:

当灰色对象要删除一个指向白色对象的引用时,就将该要删除引用关系记录下来。在并发扫描结束再以这些灰色对象为根进行扫描一次。这种做法最终导致无论关系删除与否,都会按照垃圾收集器开始扫描的那一刻的对象图来进行对象搜索。

TAMS(Top at mark start)标记顶部

G1收集器中的概念,G1为每个region设计两个TAMS的指针,用于在并发回收阶段新的对象的分配。在回收阶段新对象分配的内存地址将落在region的两个TAMS指针之间。G1默认在两个指针之间的对象是存活的,不对其进行垃圾回收。

http://www.xdnf.cn/news/205291.html

相关文章:

  • 数据库原理及应用mysql版陈业斌实验三
  • IOS 国际化词条 Python3 脚本
  • tarjan缩点+强联通分量
  • 【无报错,亲测有效】如何在Windows和Linux系统中查看MySQL版本
  • 0429/AIGC model mark Blog
  • Ansible安装配置
  • Open WebUI 设置通过硅基流动访问 DeepSeek v3 教程​
  • Hadoop 和 Spark 生态系统中的核心组件
  • AIGC(生成式AI)技术全景图:从文本到图像的革命
  • 技术白皮书:Oracle GoldenGate 优势
  • [特殊字符]OCR,给交通领域开了“外挂”?
  • Kivy使用uniad原生sdk 1,构建项目与选型
  • IDEA新版本Local Changes
  • Android 实现一个隐私弹窗
  • GitHub Actions 自动化部署 Azure Container App 全流程指南
  • 257. 二叉树的所有路径
  • 【Linux】Linux内核模块开发
  • 深入蜂窝物联网 第四章 Cat-1 与 5G RedCap:带宽、低时延与未来趋势
  • redis 有序集合zrange和zrangebyscore的区别
  • Android ndk 编译opencv后部分接口std::__ndk1与项目std::__1不匹配
  • 【LeetCode 热题 100】矩阵置零 / 螺旋矩阵 / 旋转图像 / 搜索二维矩阵 II
  • 【Vagrant+VirtualBox创建自动化虚拟环境】Ansible测试Playbook
  • springboot 框架把 resources下的zip压缩包, springboot 项目启动后解压到项目根目录工具类
  • DeepSeek主动学习系统:低质量数据炼金术的工程化实践
  • runpod team 怎么设置自己的ssh key呢?
  • LLamaFactory如何在Windows系统下部署安装训练(保姆级教程)
  • 松下机器人快速入门指南(2025年更新版)
  • Kotlin-高阶函数,Lambda表达式,内联函数
  • IntelliJ IDEA 2024.3.1 for Mac 中文 Java开发工具
  • 狼人杀中的智能策略:解析AI如何理解复杂社交游戏