JVM 的垃圾回收机制以及垃圾回收算法的详解

目录

1、JVM 的垃圾回收机制

2、识别垃圾

2.1、引用计数

2.2、可达性分析

3、垃圾回收算法

3.1、标记-清除

3.2、复制算法

3.3、标记-整理

4、分代回收



1、JVM 的垃圾回收机制

对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言,其生命周期与相关线程有关,随线程而生,随线程而灭。并且这三个区域的内存分配与回收具有确定性,因为当方法结束或者线程结束时,内存就自然跟着线程回收了。

因此有关内存分配和回收关注的为堆区和方法区这两个区域。

垃圾回收,就是回收内存。而 JVM 中的内存又分为好几块:
1、程序计数器,由于程序计数器占用的内存空间小,不需要“垃圾回收”。
2、栈区,局部变量都是在代码块执行结束后自动销毁,这和“垃圾回收”没有关系。
3、元数据区 / 方法区,一般都是涉及到“类加载”,很少涉及到“类卸载”,少量使用到“垃圾回收”。
4、堆区,“垃圾回收”的主要战场。

2、识别垃圾

想要回收垃圾,首先要识别出垃圾。在 Java 中,使用对象一定需要通过引用的方法来使用(除了匿名对象,执行完匿名对象那行代码后,对应的对象就会被当作垃圾),如果一个对象没有任何引用指向它,就视为是无法被代码使用的,即可以当作垃圾

但是,如果代码复杂一些,这些引用的生命周期各不相同,此时识别垃圾的判定过程就会复杂一些。为了解决这个问题,引入了两种解决方法:

2.1、引用计数

给每个对象安排一个额外的空间,空间里要保存当前这个对象有几个引用。这种思想虽然并没有在 JVM 中使用,但是广泛应用于其他主流语言的垃圾回收机制中(Python、php)。

 引用计数机制,是一个简单有效的机制,但是存在两个关键的问题:

  • 问题一:消耗额外的内存空间。
  • 问题二:引用计数可能会产生“循环引用”的问题,此时引用计数就无法正常工作。所谓“循环引用”是指类似于:一个类中的一个成员变量指向另一个类的引用,另一个类中的成员变量同样又指向这个类的引用,当将原先引用类的变量置空,此时引用计数依然不为0。

上述代码出现了问题,此时两个对象的引用计数都不是0,不能被 GC 回收掉,但是这两个对象又无法使用,出现了类似“死锁”的情况,这也是 Java 不用引用计数的原因之一。

2.2、可达性分析

本质上是用“时间”换取“空间”,相比引用计数需要消耗更多的额外空间,但总体来说是可控的,不会产生类似“循环引用”的问题。

在写代码的过程中会定义很多变量,就可以从这些变量作为起点入手,尝试进行“遍历”,所谓遍历就是沿着变量中持有的引用类型的成员,再进一步的往下进行访问

JVM 中存在专门的扫描线程,会不停的尝试对代码中已有的变量进行遍历,尽可能多的访问到对象。

使用上图举例,root 指向这棵二叉树的根节点,如果代码中出现了 root.right.right = null,此时二叉树与 f 节点断开,无法再使用 root 出发进行遍历操作访问 f 了,此时就说 f 节点为 “不可达” ,即可称为是垃圾;同样的代码中出现 root.right = null,此时二叉树与 c 节点断开,此时无法使用 root 遍历到达 c 节点,自然也无法到达 f 节点,此时就说 c 和 f 都是垃圾。

因此,所有能被访问到的对象,自然就不是垃圾了,反之剩下遍历了一圈也访问不到的对象,就是垃圾。

3、垃圾回收算法

把标记为垃圾的对象的内存空间进行释放,主要的释放方式有三种

3.1、标记-清除

把标记为垃圾的对象直接释放掉(最朴素的做法),但是会产生内存碎片。如果存在很多内存碎片,很可能导致申请内存空间失败的情况。
因此一般不会使用这种方案,因为“内存碎片问题”是比较致命的

3.2、复制算法

核心是不直接释放内存,而是把不是垃圾的对象,复制到内存的另外一半中,然后再整体将左则空间整体释放掉。

复制算法确实能够规避内存碎片问题,但是也有缺点:

  • 因为需要留有空间进行复制操作,总的可用内存变少了。
  • 如果每次要复制的对象比较多,此时复制的开销就会很大。(只有当该轮 GC 过程中,有大量对象被释放,少数对象存活,此时才适合使用“复制算法”) 

3.3、标记-整理

类似于顺序表删除中间元素的操作(向前搬运),通过这个过程也能够有效解决内存碎片问题,也没有复制算法需要浪费很多空间,但是搬运内存的开销非常大

由于这三种释放方式都存在各自的问题,因此 JVM 并没有直接使用上述方式,而是结合上述思想取长补短,做出了综合性方案,称为“分代回收”。

4、分代回收

引入了“对象的年龄”这样的概念,JVM 中有专门的线程负责周期性扫描/释放,一个对象如果被线程扫描一次,并且“可达性分析”证明可达(不是垃圾),此时将该对象的年龄属性 + 1(初始年龄为0)。JVM 中根据年龄的差异,将整个堆内存分成两个大的部分,“新时代”和“老年代”。而新生代区中又分为“伊甸区”“生存区s0”“生存区s1”

当代码中 new 出一些对象,这些对象会先被创建在伊甸区,而在伊甸区中的对象,绝大部分会死去,只有少量存活,因此此处的垃圾回收算法使用“复制算法”

然后经过一轮 GC 扫描后,会有少数存活的对象通过“复制算法”拷贝到生存区(有两个生存区),后续的 GC 扫描线程会对伊甸区和生存区都进行扫描,伊甸区中少数存活的对象同样会进入生存区,而生存区中仍然存活的对象会拷贝到另外一个生存区。

当对象的年龄达到一定阈值(一般情况默认 15 次)并且依然存活时,此时 JVM 就会认为该对象的生命周期大概率很长,就将这个对象从生成区拷贝到老年代区。

而在老年代的对象,GC 扫描的频率会大大降低。在老年代中结束的对象会按照 JVM的“标记整理”或者“标记清除”方法释放内存。

【博主推荐】 

对 JVM 的类加载机制以及寻找字节码文件的“双亲委派模型”的理解-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136529700?spm=1001.2014.3001.5501【网络编程】理解客户端和服务器并使用Java提供的api实现回显服务器-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136322678?spm=1001.2014.3001.5501【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136288256?spm=1001.2014.3001.5501

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!

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

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

相关文章

FairScale 库测试实验(一)-- 大模型训练基础之模型并行

DDP的分布式训练方法采用数据并行方式,相当于通过增大数据的batch来加快训练。但对于大模型(LLM)来说,DDP已经不适用了。因为LLMs的模型本身太大,一块GPU都放不下怎么可能去复制从而实现数据并行呢。所以LLM的训练采用…

MySQL--优化(索引--索引失效场景)

MySQL–优化(索引–索引失效场景) 定位慢查询SQL执行计划索引 存储引擎索引底层数据结构聚簇和非聚簇索引索引创建原则索引失效场景 SQL优化经验 常见的索引失效场景 1、场景准备: 给 tb_user 表创建联合索引,字段为&#xff1…

对于SG90三线舵机的介绍

目录 一、什么是舵机 PWM 生成PWM波的原理 二、SG90工作原理 180度舵机 360度舵机 三、相关代码 main.c timer0.c timer0.h delay.h 一、什么是舵机 “舵机是一种直流微型伺服电机,它能够接收并响应控制信号,实现角度或位置的精确控制。舵机…

【中间件】RabbitMQ入门

📝个人主页:五敷有你 🔥系列专栏:中间件 ⛺️稳中求进,晒太阳 MQ的优劣: 优势 应用解耦:提升了系统容错性和可维护性异步提速:提升用户体验和系统吞吐量消峰填谷&#xff1…

高电平复位电路工作原理详解

单片机复位电路的作用是:使单片机恢复到起始状态,让单片机的程序从头开始执行,运行时钟处于稳定状态、各种寄存器、端口处于初始化状态等等。目的是让单片机能够稳定、正确的从头开始执行程序。一共分为:高电平复位,低…

SRC学习-成为赏金猎人

你是否对漏洞挖掘充满好奇?零基础或有基础但想更进一步?想赚取可观的漏洞赏金让自己有更大的自由度? 那么,不妨了解下土拨鼠的安全屋 这或许也是你成为漏洞赏金猎人的第一课。 逻辑漏洞挖掘手法与创新思路,带你突破…

漏洞复现-蓝凌LandrayOA系列

蓝凌OA系列 🔪 是否利用过 优先级从高到低 发现日期从近到远 公司团队名_产品名_大版本号_特定小版本号_接口文件名_漏洞类型发现日期.载荷格式LandrayOA_Custom_SSRF_JNDI漏洞 LandrayOA_sysSearchMain_Rce漏洞 LandrayOA_Custom_FileRead漏洞

【C++庖丁解牛】STL简介 | string容器初次见面

📙 作者简介 :RO-BERRY 📗 学习方向:致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 📒 日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持 目录 1. 什么是STL2. STL的…

Spring Boot工作原理

Spring Boot Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。也就是说,它并不是用来替代 Spring 的解决方案,而是和 Spr…

SpringMVC04、Controller 及 RestFul

4、Controller 及 RestFul 4.1、控制器Controller 控制器复杂提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。控制器负责解析用户的请求并将其转换为一个模型。在Spring MVC中一个控制器类可以包含多个方法在Spring MVC中,对于Contr…

FPGA高端项目:FPGA基于GS2971的SDI视频接收+GTX 8b/10b编解码SFP光口传输,提供2套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI接收转HDMI输出应用本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收HLS图像缩放Video Mixer多路视频拼接应用本方案的SDI接收OSD动态字符叠加…

CorelDRAW Graphics Suite2024专业图形设计软件Windows/Mac最新25.0.0.230版

CorelDRAW Graphics Suite 2024是一款专业的图形设计软件,它集成了CorelDRAW Standard 2024和其他高级图形处理工具,为用户提供了全面的图形设计和编辑解决方案。 该软件拥有强大的矢量编辑功能,用户可以轻松创建和编辑矢量图形,…

JavaScript数组常见实例方法:forEach、filter、map、reduce、find、every等

博客背后的故事 其实我23年7月就学过这些数组方法了,但是为什么24年3月才做笔记呢?这就要讲一个小故事了(不想听故事的同学自行拖动滚动条) 24年年初我和两个队友合作开发一个小程序。JavaScript中数组的实例方法我已经学了很久…

集万千优点于一身的Haproxy集群,你还不了解?

一、HAProxy介绍 HAProxy是法国开发者威利塔罗(Willy Tarreau)在2000年使用C语言开发的一个开源软件,是一款具备高并发(一万以上)、高性能的TCP和HTTP负载均衡器,支持基于cookie的持久性,自动故障切换,支持正则表达式及web状态统…

怎么做不限扫码次数的文件活码?文件可长期扫描展现下载

如何制作不限扫码次数的文件二维码呢?将文件转二维码后分享给其他人,是现在非常方便的一种文件传输方式。很多小伙伴在制作文件二维码的时候,比较担心的一个问题,就是二维码可以扫码的次数,担心达不到自己预期的效果&a…

C++ 打印输出十六进制数 指定占位符前面填充0

C 打印十六进制数据&#xff0c;指定数据长度&#xff0c;前面不够时&#xff0c;补充0. 代码如下&#xff1a; #include <iostream> #include <iomanip> #include <cmath>using namespace std;int main() {unsigned int id 0xc01;unsigned int testCaseId…

Docker部署SimpleMindMap结合内网穿透实现公网访问本地思维导图

文章目录 1. Docker一键部署思维导图2. 本地访问测试3. Linux安装Cpolar4. 配置公网地址5. 远程访问思维导图6. 固定Cpolar公网地址7. 固定地址访问 SimpleMindMap 是一个可私有部署的web思维导图工具。它提供了丰富的功能和特性&#xff0c;包含插件化架构、多种结构类型&…

【C++】inline内联函数 VS #define宏

文章目录 1. 内联概念2. 内联特点3. 宏的优缺点 1. 内联概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;无函数建立栈帧的开销&#xff0c;内联函数提升程序运行的效率。 在release模式下&#xff0c;默认展开生效。 在…

时序报告Report_timing_summary之一步精通配置选项使用

目录 一、前言 二、配置选项概览图 三、配置选项 3.1 Options 3.1.1 report 3.1.2 path limits 3.1.3 path display 3.2 Advanced 3.2.1 report 3.2.3 miscellaneous 3.3 Timer Settings 3.4 共有部分 四、工程示例 4.1 工程设计代码 4.2 约束文件 4.3 Option…

Stable Diffusion WebUI 中英文双语插件(sd-webui-bilingual-localization)并解决了不生效的情况

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里。 大家好&#xff0c;我是水滴~~ 本文介绍一款中英文对照插件 sd-webui-bilingual-localization&#xff0c;该插件可以让你的 Stable Diffusion WebUI 界面同时显示中文和英文&#xff0c;让我…