可达性分析、三色标记、新生代、老年代的关系是什么

news/2024/5/11 2:05:05

        jvm提供了垃圾回收器进行垃圾回收,垃圾回收器的职责就是回收内存中不再被引用的对象,以便释放内存。垃圾回收器利用可达性分析算法去分析哪些对象需要被回收,可达性分析算法是这样的:首先一些对象被定义为gc roots,然后沿着这些gc roots对象的引用链往下查找,无法通过gc roots的引用链被查找到的对象即为不可达对象。三色标记是可达性分析算法的一种实现,它包含三种颜色:白色、灰色和黑色,不同颜色有不同的意义,在三色标记结束之后,gc将去回收白色的对象。我们知道,在jvm的内存模型中,堆内存是gc回收的重要区域,因为大部分的对象都是保存在堆中的,而堆又分成了三大部分:新生代、老年代和永久代。新生代和老年代的标记回收算法不同,新生代用标记-复制算法,老年代用标记-清除算法,不论哪种算法,标记都是首先需要做的,只有在标记之后,gc才能够知道哪些对象是需要被回收的。

        在讲标记过程之前,先讲一下几个概念:gc roots、三种颜色的意义、新生代、老年代

        会被定义为gc roots的对象有

                1、虚拟机栈中引用的对象:虚拟机栈中保存的是一个个的栈桢,每个栈桢中保存的是

        它对应的方法的局部变量、部分运行结果、方法出口等信息,局部变量所引用的对象会被

        定义为gc roots;

                2、本地方法栈中引用的对象:也就是native方法中引用的对象会被定义为gc roots;

                3、方法区中类的静态变量和常量引用的对象会被定义为gc roots。

        三种颜色的意义

                白色:未被标记的对象

                灰色:已被标记,但是还有至少一个直接引用未被标记的对象

                黑色:已被标记,并且所有直接引用均已被标记的对象

        新生代:新生代中保存的是大部分的新被创建的对象【新创建的对象如果很大的话,不会保存在新生代中,会被保存到老年代中】,这些对象大部分都是朝生夕死,因此在新生代中会有大量的minor gc;新生代又划分为三个区域;Eden区、survivor from区、survivor to区,新生代用标记-复制算法进行minor gc,在执行minor gc的时候,会将Eden区和survivor from区中被标记为存活的对象转移到survivor to区中,然后将Eden区和survivor from区清空,然后将存活的对象年龄加1,如果某个对象年龄达到了15,则将这个对象转移到老年代;年龄计算完毕,将survivor from和survivor to两个区域的功能互换,那么下一次minor gc的时候就是将Eden区和survivor to区的存活对象转移到survivor from区,然后进行年龄的计算了。

        老年代:老年代中保存的是年龄比较大的对象以及占用内存比较大的新创建的对象,老年代比较稳定,不会进行大量的major gc,但是当要保存一个比较大的新创建的对象的时候,如果没有足够大的连续内存去保存它,那么会触发major gc,以便腾出空间去保存它;新生代在执行minor gc时有可能导致年龄大的对象转移到老年代,如果这时候老年代没有足够的空间了,那么也会触发老年代执行major gc。老年代用标记-清除算法执行major gc,它会扫描老年代中所有的对象,标记出存活的对象,然后将没有标记的对象回收,当major gc之后依然没有足够的空间去保存新的对象的时候,就会抛出OOM异常。

        具体而言,标记回收的过程是这样的

        我们知道,java中的线程分为用户线程和守护线程,用户线程是执行具体任务的线程,守护线程是为用户线程服务的后台线程,当我们启动一个用户线程的时候,jvm会自动地启动一个进行垃圾回收的守护线程,用于回收这个用户线程执行过程中产生的垃圾,这个垃圾回收线程在开始回收对象之前,会对对象进行三色标记,三色标记的过程

        1、初始的时候,除了gc roots对象是黑色的以外,其他所有的对象都是白色的

        2、将gc roots对象直接引用的白色对象标记为灰色

        3、将灰色对象直接引用的白色对象标记为灰色,并将灰色对象本身标记为黑色

        4、如果某个灰色对象已经没有未被标记的直接引用了,那么将这个对象标记为黑色

        5、如果依然有灰色对象存在未被标记的直接引用,则重复上面的从3开始的标记步骤,直到没有灰色对象存在

        这时只剩下了黑色和白色对象,gc要回收的便是白色对象

        但其实这个标记过程是会有问题的,因为执行三色标记的守护线程是和它对应的用户线程并发执行的,那么就会有并发标记的问题:如果在并发标记过程中,对象的引用关系发生了变化,那么就有可能产生多标和漏标的问题。

        多标:如果某个之前被引用的对象a又不被引用了,而引用关系改变时a对象已经被标记为黑色了,那么a对象就被多标了。多标的问题不大,顶多就是a对象在这次的gc中逃逸掉了,那么它可以在下一轮gc中被回收掉

        漏标:如果某个白色对象n由被对象a引用变为被对象b引用,并且引用关系改变的时候,a是灰色的,而b是黑色的,那么就会有问题,因为新引用它的b已经是黑色了,所以已经无法通过b来标记对象n了,那么一直到三色标记结束,n对象依然是白色,就会导致对象n被gc回收,这就导致了不该被回收的对象被回收掉了,会使程序出现严重的bug。

        解决漏标的问题,可以用写屏障+增量更新方案:

        增量更新:当某个黑色的对象black去新引用一个对象obj时,会将这个黑色对象black标记为灰色,这样obj就不会被漏标了。CMS垃圾回收器就是使用了增量更新。

        需要注意的是,即便某个对象被标记为不可达【白色】了,它也不一定真的会被回收,它还有可能通过一个方法翻盘,这个方法叫做finalize。

        用finalize翻盘:

        finalize是定义在Object类中的一个方法,它的作用是在回收对象之前做一些诸如关闭资源的操作,这个方法只可能被执行一次,因为Object类是所有类的父类,所以任何类都可以去重写这个方法。

        gc在对对象进行了第一次标记之后,还要去判断这个对象的finalize方法是否有必要执行,只有对象重写了finalize方法并且它的finalize方法还未执行过,它才有必要执行finalize方法;如果某个对象的finalize方法没有必要执行,那么它的命运就决定了,它肯定会被gc回收;如果某个对象的finalize方法有必要执行,那么这个对象会被放在一个专用队列F-Queue中,jvm会启动一个专门的低优先级的线程去执行这个队列中所有对象的finalize方法,如果一个对象在finalize方法中被重新引用了,那么它会被移出F-Queue,也就是它逃避掉了被gc清除的命运;而那些在finalize方法中未被重新引用的对象,在finalize方法执行完毕之后,会被进行第二次标记,这些对象就真的要被清除了。


http://www.mrgr.cn/p/15504606

相关文章

SSM整合

文章目录 Spring Spring MVCMyBatis整合目录结构引入Maven包web.xml文件导入spring_mvc.xml**spring_mvc.xml****中添加**json**返回编码**UTF-8**导入spring_config.xml文件导入mybatis.xml文件创建pojo对象创建Mapper.xml创建Service创建Controller Spring Spring MVCMyBatis…

Linux系统使用(超详细)

目录 Linux操作系统简介 Linux和windows区别 Linux常见命令 Linux目录结构 Linux命令提示符 常用命令 ls cd pwd touch cat echo mkdir rm cp mv vim vim的基本使用 grep netstat Linux面试题 Linux操作系统简介 Linux操作系统是和windows操作系统是并列…

【论文笔记】KDD2019 | KGAT: Knowledge Graph Attention Network for Recommendation

Abstract 为了更好的推荐,不仅要对user-item交互进行建模,还要将关系信息考虑进来 传统方法因子分解机将每个交互都当作一个独立的实例,但是忽略了item之间的关系(eg:一部电影的导演也是另一部电影的演员&#xff09…

【数据结构与算法】斐波那契查找(黄金分割法)

斐波那契查找(黄金分割法) 黄金分割点是指把一条线段分割成两部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是 0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割,也称为中外比…

人工智能安全-2-非平衡数据处理

0 提纲 现象与原因非平衡数据处理方法概览数据预处理层面特征层算法层面1 现象与原因 非平衡数据分类问题:在网络信息安全问题中,诸如恶意软件检测、SQL注入、不良信息检测等许多问题都可以归结为机器学习分类问题。这类机器学习应用问题中,普遍存在非平衡数据的现象。 产…

Spring MVC拦截器和跨域请求

一、拦截器简介 SpringMVC的拦截器(Interceptor)也是AOP思想的一种实现方式。它与Servlet的过滤器(Filter)功能类似,主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用…

618技术揭秘 - 大促弹窗搭投实践 | 京东云技术团队

背景 618 大促来了,对于业务团队来说,最重要的事情莫过于各种大促营销。如会场、直播带货、频道内营销等等。而弹窗作为一个极其重要的强触达营销工具,通常用来渲染大促氛围、引流主会场、以及通过频道活动来提升频道复访等。因此&#xff0…

管理ceph集群

文章目录 ceph的常用命令查看集群状态查看pg的状态查看mon节点状态查看osd的通用命令查看osd的容量查看osd池写入文件测试查看池的属性查看文件映射过程 添加磁盘删除磁盘 ceph的常用命令 查看集群状态 ceph osd pool application enable pool-name rbd #将池启用rbd功能 ceph…

华为数通HCIA-网络模型

TCP 网络通信模式 作用:指导网络设备的通信; OSI七层模型: 7.应用层:由应用层协议(http、FTP、Telnet.)为应用程序产生对应的数据; 6.表示层:将应用层产生的数据转换成网络设备看…

实战:Docker+Jenkins+Gitee构建CICD流水线

文章目录 前言Jenkins部署创建Jenkins docker-compose配置maven源启动Jenkins容器安装插件Gitee ssh公匙配置与测试项目提交 Jenkins创建流水线写在最后 前言 持续集成和持续交付一直是当下流行的开发运维方式,CICD省去了大量的运维时间,也能够提高开发…

【Linux】关于Bad magic number in super-block 当尝试打开/dev/sda1 时找不到有效的文件系统超级块

每个区段与 superblock 的信息都可以使用 dumpe2fs 这个指令来查询的! 不过可惜的是,我们的 CentOS 7 现在是以 xfs 为默认文件系统, 所以目前你的系统应该无法使用 dumpe2fs 去查询任何文件系统的。 因为目前两个版本系统的根目录使用的文…

redis基础总结(数据类型)

Redis十大数据类型 String String 是redis最基本数据类型,一个key对应一个value. String类型是二进制安全的,意思是Redis的string类型可以包含任何数据,比如jpg图片或者序列化的对象; String类型是最基本的数据类型,一个redis中字符串value最多是512M; String类型在redis底层…

力扣天天练--week3-LeetCode75

topic75-9-t443:压缩字符串 题目描述: 给你一个字符数组 chars ,请使用下述算法压缩: 从一个空字符串 s 开始。对于 chars 中的每组 连续重复字符 : 如果这一组长度为 1 ,则将字符追加到 s 中。 否则,需…

企业知识文档管理+群晖nas安全云存储

企业知识管理系统,利用软件系统或其他工具的企业管理方法,利用软件系统或其他工具,对组织中大量的有价值的方案、策划、成果、经验等知识进行分类存储和管理,积累知识资产避免流失,促进知识的学习、共享、培训、再利用…

C++ ——STL容器【list】模拟实现

代码仓库: list模拟实现 list源码 数据结构——双向链表 文章目录 🍇1. 节点结构体🍈2. list成员🍉3. 迭代器模板🍊4. 迭代器🍋5. 插入删除操作🍌5.1 insert & erase🍌5.2 push_…

【C++】开源:跨平台轻量日志库easyloggingpp

😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍跨平台轻量日志库easyloggingpp。 无专精则不能成,无涉猎则不能通。。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下&am…

论文笔记--GloVe: Global Vectors for Word Representation

论文笔记--GloVe: Global Vectors for Word Representation 1. 文章简介2. 文章概括3 文章重点技术3.1 两种常用的单词向量训练方法3.2 GloVe3.3 模型的复杂度 4. 文章亮点5. 原文传送门6. References 1. 文章简介 标题:GloVe: Global Vectors for Word Representa…

<MySQL> Centos 7环境安装MySQL

Centos 7环境安装MySQL 1.卸载不要的环境 停止MySQL服务 systemctl stop mariadb.service systemctl stop mysqld禁止MySQL服务开机自启 systemctl disable mysqld卸载MySQL软件包 yum remove mysql-server mysql-client删除MySQL数据目录 rm -rf /var/lib/mysql清理MySQ…

安装了pyintaller后出现:‘pyinstaller‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

2023年7月31日,周一上午 我昨天晚上也遇到了这个问题,后来解决了 目录 出错原因解决方法怎么找到Scripts文件夹 出错原因 出现这个错误是因为你没给python的Scripts文件夹添加环境变量, Scripts存放着pip安装包时产生的可执行文件。 解决…