说说JVM的垃圾回收机制

简介

垃圾回收机制英文为Garbage Collection, 所以我们常常称之为GC。那么为什么我们需要垃圾回收机制呢?如果大家有了解过Java虚拟机运行时区域的组成(JVM运行时存在,本地方法栈,虚拟机方法栈,程序计数器,堆,方法区五个区域),我们知道本地方法栈,虚拟机方法栈和程序计数器是线程独有的,即随着线程的存在而存在,随着线程的消亡而消亡,其内存分配和回收都具备确定性所以不用过多考虑回收问题。但是Java堆(主要存放对象)和方法区(存放常量和静态的属性,方法,对象)由于只有在运行时才知道有多少对象,所以这部分内存的分配和回收时动态的,此时就需要我们的垃圾回收机制来进行处理。

Point 1:如何判断对象是否存活

目前有两种方法来判断对象是否存活,第一种是引用计数算法,第二种是可达性分析算法。接下来我们对他们逐一进行讲解:

  • 引用计数算法:在对象中添加一个引用计数器,每当该对象被引用,计数器值就加一;引用失效就减一;当计数器为0,该对象就是不可使用的。虽然占用了一些额外空间,但是优点是效率高,但是存在一个问题,即:当两个对象互相引用时,虽然他们都不能被访问了,但是由于互相引用的原因,导致计数器为1,所以会成为漂浮垃圾,无法被回收。
  • 可达性分析算法:即在程序进行到某一点时,判断该对象能否被引用。我们可以举例结合图像来说明,本质上我们通过GC Root Set 来维护一个根集合,其中存在很多根对象节点,从这些节点向下走,经过的路径称为引用链,如若链中节点对根节点不可达,那么说明该对象不可使用了。该算法不能在应用程序活跃运行时执行对象追踪,因为执行上下文和对象图都在持续变化中,应用程序执行与可达性分析是一个竞态条件
  • 固定可做GC Roots 对象包括以下几种:
    • 在虚拟机栈中引用的对象
    • 在方法区中静态属性引用的对象
    • 在方法区中常量引用的对象
    • 在本地方法栈中JNI引用的对象
    • Java虚拟机内部的引用
    • 所有被同步锁持有的对象
    • 反射Java虚拟机内部情况的 JMXBean, JVMTI中注册的回调、本地代码缓存等

引用分类:

  1. 强引用
  2. 软引用
  3. 弱引用
  4. 幻影引用

JVM判断对象死亡过程

要真正宣布一个对象死亡需要精力两次标记过程,如若一个对象发现对于 GC Root 是不可达的,那么它将会被第一次标记。如若对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过了,那么虚拟机将这两者情况视作“没必要执行”。如若对象被确定为需要进行finalize()方法,那么该对象会被放到一个称为F-Queue的队列之中,并由一个新线程去执行finalize()方法。此时虚拟机还会对F-Queue队列中的对象进行一次小规模标记,如若对象在finalize()方法中成功自救,即连接上可达GC Root 对象的节点,即可逃脱回收。

需要注意的一点是:任何一个对象的finalize()方法都只会被系统自动调用一次,意味着如果第一次逃脱了,那么第二次如果被标记就会直接回收,不在进行finalize()方法。

Point 2:垃圾收集算法

主要有两类:“引用计数式” -- 直接垃圾收集 & “追踪式垃圾收集” -- 间接垃圾收集

分代收集

根据弱分代假说强分代假说,我们的收集器应该将Java堆划分出不同的区域,然后将回收对象依据其熬过垃圾收集过程的次数将其分配到不同区域中存储。所以目前我们的Java虚拟机一般存在新生代老年代。根据跨代引用假说我们可以得知跨代引用虽然存在,但是较于同代引用只占少数,因此我们引出了一个新的数据结构——记忆集,该数据结构用于吧老年代划分为若干小块,标记老年代哪一块内存存在跨代引用,如若新生代发生了GC的话,只用将对应小块内存加入到GC Root进行扫描就ok了。

注:新生代收集(Minor GC/ Young GC) / 老年代收集(Major GC/ Old GC) / 混合收集(Mixed GC) / 整堆收集(Full GC)

说了这么多关于收集器的分代概念,大家是否对虚拟机如何进行收集有疑问呢?接下来就来说说关于虚拟机的收集算法。主要分为三种:标记清除法,标记复制法,标记整理法。

  • 标记——清除算法:顾名思义,该算法分为两步,首先标记所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
    • 缺点:1. 执行效率不太稳定,会随着对象数量增长降低回收(标记和回收)效率。 2. 存在内存空间碎片化问题,由于每次标记和清楚都是碎片化的操作,这样就会引出一个问题,当我们需要分配一个大的对象的时候,就无法在新生代找到一个合适的区域放置这个对象,这时会触发另外一次垃圾回收动作。
  • 标记——复制算法:为了解决上一算法存在的缺点1,我们提出了该算法,又被称为半区复制算法,即将内存容量分为两个等大区域,每次只使用其中一块,如若被使用那块被用完了就将还存活的对象迁移至另一块内存空间,这个算法也避免了上述算法的缺点2。
    • 但是同样的这个算法也存在缺点:1. 大量的内存复制开销。2. 针对大多数对象都是存存活的状况,使用标记复制算法就欠妥了。3. 将可用内存空间变为内存的一半。
    • 所以针对新生代,朝生夕灭的特点,我们可以判断出标记复制算法可以用于新生代而且由于对象存活时间短数量少,我们可以将内存空间的划分做一些改变,比如按照 8:1 的比例进行分配,选取一个占比为 1/ 9 的空间作为固定的存放存货对象的空间。但是这样就会引出一个新问题,如果超过了 1/9 空间的对象存活,那么就存放不下了。这时我们就需要内存分配担保机制将新生代无法存放的存活对象直接存入老年代。
  • 标记——整理算法:由上文可知,标记复制算法的变型用于新生代回收特别方便,那么对于我们的老年代呢?根据老年代特性,我们知道其中大部分对象都是存活的,只会有少量对象需要回收。我们可以使用标记——整理的方法来解决,即标记活的对象,然后将存活对象移至一端,然后将须回收对象移至一端,我们就只清除这一端就ok了。但是这样也带来一个问题,既然老年代大多数对象都是存活的,那么每次这样移动操作对系统消耗较大而且也会导致"Stop The World" 发生。所以我们有了一种新的办法来处理老年代对象,即让虚拟机在大多数时间都采用标记——清除算法,知道内存碎片已经影响到对象分配了,我们就采用标记——整理算法对空间进行一次整理,得到一个规整的内存空间。

Point 3:HotSpot 算法实现细节

根节点枚举

由于需要查询对象引用关系,所有的收集器在根节点枚举这一步骤都是要暂停用户线程的。由于当前主流Java虚拟机采用的都是准确式垃圾收集,用户线程停顿后不需要逐个检查执行上下文,只需得到哪些地方存储着对象引用。例如HostSopt采用的就是OopMap来记录对象信息。

安全点

在OopMap的协助下,HotStop可以快速准确的完成GC Root枚举,但是导致OopMap变化的指令很多,如若每个都生成OopMap那么将会需要大量额外空间。事实上HotSopt也只在安全点进行OopMap生成,即只有到了安全点,才可以暂停用户线程进行GC。中断也有两种方式:

  1. 抢断式中断:抢断式中断不需要线程执行代码主动配合,发生GC时,会中断所有的用户线程,如果发现有用户线程中断的地方不在安全点上,就恢复这条线程知道他到达安全点再度中断。
  2. 主动式中断:不直接对线程操作,仅仅简单的设置一个标志位,每个线程都不停的轮询这个标志位,一旦发现标志位为中断就主动挂起。这个标志位和安全点是重合的。

安全区域

可以理解为加长版的安全点。如果程序在执行,它可以运行到安全点,如果程序不执行,如线程处于Sleep或者Blocked状态,这时候线程无法响应虚拟机中断请求,自然就无法走到安全点去挂起自己。所以安全区就是在某一段代码中,引用关系不会发生变化,因此,在这个区域中任意地方开始垃圾收集是安全的。线程进入安全区域会标识自己,离开时会检查虚拟机是否完成了根结点枚举,如若没有收到就会被要求一直等待直到收到可以离开的信号。

Point 4:记忆集与卡表

在前文中我们提到了记忆集的概念,即用于解决查询跨代引用代价过大问题而引申出来的数据结构。

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

有三种精度,分别是:1.字节精度,2. 对象精度, 3. 卡精度。三者中最常用的就是卡精度,顾名思义,采用卡表来实现记忆集,它定义了记忆集的记录精度与堆内存映射关系。可以联想为Java中Map。一个卡页通常包括不止一个对象,如若卡页里面有超过一个对象字段的跨代指针,那么就将对应卡表的数组元素的值设置为1,称为这个卡表变脏(dirty) 否则就是0。

卡表变脏的实际就是有其他分代区域中的对象引用了本区域的对象时,卡表就会变脏。

Point 5:写屏障

我们知道了卡表变脏时机,那么我们将如何来将卡表更新呢?由于编译过程是机器码,所以虚拟机就不方便介入,于是在我们的HotSpot中存在一个写屏障,可以看作虚拟机层面对“引用类型字段赋值”这个动作的AOP切面,在引用对象赋值时会产生一个环形通知,赋值前后都在写屏障覆盖范畴内。

一些收集器

垃圾回收器我就不过多赘述了,本质上就是对垃圾回收算法的实践。有很多版本比如 CMS, ZGC等等,如读者有兴趣可自行搜索学习。

参考资料:

《深入理解Java虚拟机》

《虚拟机设计与实现,以JVM为例》

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

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

相关文章

linux安全--CentOS7安装Tomcat,远程管理ManagerApp

目录 1.Tomcat安装 2.Tomcat远程管理 1.Tomcat安装 下载安装包并解压 tar xf apache-tomcat-7.0.54.tar.gz -C /usr/local/apache-tomcat_7.0.54/tomcat启停 启动 ./startup.sh 停止 ./shutdown.sh 2.Tomcat远程管理 找到tomcat文件夹中webapps/manager/META-INF/contex…

(黑马出品_高级篇_04)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式

(黑马出品_高级篇_04)SpringCloudRabbitMQDockerRedis搜索分布式 微服务技术——可靠性消息服务 今日目标服务异步通信-高级篇1.消息可靠性1.1.生产者消息确认1.1.1.修改配置1.1.2.定义Return回调1.1.3.定义ConfirmCallbac…

temu英国电商市场洞察:2月份商品销售数据分析Python数据采集Api

文章目录 引言可视化分析数据展示商品类目占比分析销售额分析价格区间占比分析各类目新品占比分析 写在最后 引言 在美国市场稳步增长基础上,Temu也不断加快全球步伐,现已进入47个国家,光23年9月份就进驻了10个国家,创造单月扩张国…

FileZillaClient连接被拒绝,无法连接

1.ECONNREFUSED - 连接被服务器拒绝 2、无法连接FZ时,判断没有ssh 更新源列表: sudo apt-get update 安装 openssh-server :sudo apt-get install openssh-server 查看是否启动ssh:sudo ps -e | grep ssh

2024 前端javaScript+ES6

JavaScript 基础 1、基本数据类型: 1.1 基本数据类型: Number(数值):表示数字,包括整数和浮点数。例如:5、3.14。 String(字符串):表示文本数据&#xff…

hanlp,pyhanlp 实现 NLP 任务

目录 区别 hanlp 代码使用 pyhanlp 代码使用 在线体验:命名实体识别 | 在线演示 区别 hanlp:是 githun 官方文档提供的使用方法,也就是在线的,调用 api 的方式去实现的,可以自己申请 token,接口分为 RE…

SSA-LSTM多输入回时序预测 | 樽海鞘优化算法-长短期神经网络 | Matlab

目录 一、程序及算法内容介绍: 基本内容: 亮点与优势: 二、实际运行效果: 三、算法介绍: 四、完整程序下载: 一、程序及算法内容介绍: 基本内容: 本代码基于Matlab平台编译&a…

通过日志恢复sql server数据库

在SQL Server中,通过日志恢复数据库是一个精细的过程,主要用于在数据库出现错误、数据丢失或需要回滚到特定时间点时恢复数据。以下是一般步骤概述: 设置恢复模式: 首先,数据库必须配置为“完整恢复模式”或“大容量…

深度学习系列62:Agent入门

1 anget介绍和openai标准接口 agent的核心是其代理协同工作的能力。每个代理都有其特定的能力和角色,你需要定义代理之间的互动行为,即当一个代理从另一个代理收到消息时该如何回复。 agent目前大多使用openai标准接口调用LLM服务,说明如下。…

vim相关命令

vim 三种工作模式:命令模式、文本模式、末行模式 命令模式:通过vi hello.c 命令进入i a o 、I A O、 s S 可以切换到文本模式 ,写完后保存退出 o光标 回到下一行O光标回到上一行s删除当前字母S删除一整行A回到该行末尾处a光标回到下一个输入…

探索直播美颜SDK的未来发展方向:虚拟现实、增强现实与混合

如今,随着虚拟现实(VR)、增强现实(AR)和混合现实(MR)等技术的不断发展,直播美颜SDK的未来发展方向也将面临着更多的可能性和挑战。今天我将与大家共同探讨直播美颜SDK在虚拟现实、增…

神经网络处理器优化设计(一)

神经网络处理器优化设计,涉及到一些特殊和通用处理流程,一是降低硬件成本,二是提高性能。 一 跨层流水线调度 这里主要针对深度可分离卷积,将Pointwise conv与Depthwise卷积并行处理,好处是,减小整体流水时…

活动预告:如何培养高质量应用型医学人才?

在大数据时代与“新医科”建设的背景下,掌握先进的医学数据处理技术成为了医学研究与应用的重要技能。 为了更好地培养社会所需要的高质量应用型医学人才,许多高校已经在广泛地开展面向医学生的医学数据分析教学工作。 在“课-训-赛”育人才系列活动的…

使用Thymeleaf-没有js的html模板导出为pdf

html模板 <!DOCTYPE html> <html xmlns:th"http://www.thymeleaf.org"><head><title>PDF Template</title> </head> <body> <h1>User Information</h1> <p>Name: <span th:text"${user.name}&…

一周学会Django5 Python Web开发-Jinja3模版引擎-安装与配置

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计35条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

为什么 VSCode 不用 Qt 而要用 Electron?

为什么 VSCode 不用 Qt 而要用 Electron? 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「Qt 的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&am…

【海贼王的数据航海】探究二叉树的奥秘

目录 1 -> 树的概念及结构 1.1 -> 树的概念 1.2 -> 树的相关概念 1.3 -> 树的表示 1.4 -> 树在实际中的运用(表示文件系统的目录树结构) 2 -> 二叉树概念及结构 2.1 -> 二叉树的概念 2.2 -> 现实中的二叉树 2.3 -> 特殊的二叉树 2.4 ->…

智慧城市与数字经济:共创城市新价值

随着科技的快速发展&#xff0c;智慧城市与数字经济已成为推动城市现代化进程的重要引擎。它们不仅提升了城市治理的效率和公共服务水平&#xff0c;还为城市经济发展注入了新的活力。本文旨在探讨智慧城市与数字经济如何共同创造城市新价值&#xff0c;并分析其面临的挑战与发…

全视智慧机构养老解决方案,以科技守护长者安全

2024年2月28日凌晨1时许&#xff0c;在上海浦东大道的一家养护院四楼杂物间内发生了一起火灾事故。尽管火势不大&#xff0c;过火面积仅为2平方米&#xff0c;但这场小火却造成了1人死亡和3人受伤的悲剧。这一事件再次提醒我们&#xff0c;养老院作为老年人聚集的场所&#xff…

矩阵乘积知识

参考&#xff1a;矩阵点乘【矩阵点乘计算公式】_万动力 矩阵乘 矩阵相乘最重要的方法是一般矩阵乘积。它只有在第一个矩阵的列数&#xff08;column&#xff09;和第二个矩阵的行数&#xff08;row&#xff09;相同时才有意义 [1] 。 哈达码积 别名&#xff1a;矩阵点乘&…