JVM的垃圾回收机制(GC机制)

news2024/10/6 14:25:29

在Java代码运行的过程中,JVM发现 某些资源不需要再使用的时候,就会自动把资源所占的内存给回收掉,就不需要程序员自行操作了。“自动回收资源”就是JVM的“垃圾回收机制”,“垃圾回收机制”也称"GC机制"

对于Java代码来说,"垃圾回收机制"的回收对象就是"堆"上的对象。因为"栈"上的局部变量,跟随栈帧的生命周期,一个方法执行结束,栈帧销毁,内存也就释放了;"方法区"中的静态变量,跟随着"类"的生命周期,因此静态变量是在程序运行期间始终存在的,无需释放。那么"垃圾"就是 "堆"中的对象。

垃圾回收机制可以分为两大步骤:"找垃圾""回收垃圾"

1. 找垃圾

"找垃圾"有两种方式,分别是 引用计数(python的方式) 和 可达性分析(Java的方式)。

1.1 引用计数

对于一个new出来的对象,会单独安排一块内存空间 来保存一个计数器。这个计数器 就用来描述当前这个对象 有几个引用指向它。当计数器为0时,也就意味着没有引用指向这个对象了,那么这个对象就是"垃圾"了。

1.2 可达性分析

在Java代码运行的过程中,会有一个或一组扫描线程周期性地扫描代码中的所有对象。这个扫描线程,会从一些特定的对象出发,尽可能地进行遍历访问,把所有能够访问到的对象 标记为 可达。反之,经过扫描之后,没有被标记的对象,就是"垃圾"了。可达性分析 是周期性地进行,会消耗一定地系统资源。

2. 回收垃圾

2.1 标记清除

把找到的"垃圾"对象直接释放掉,这就是标记清除的回收方式。这种方式并不好,因为这样的回收垃圾的方法会导致内存中有很多的内存碎片。随着程序的运行,内存碎片会越来越多,这就会导致后续申请内存空间时非常困难。回收垃圾的目的本就是为了释放内存空间,从而让其它进程申请到内存空间,但这种释放内存的方式并没有达到想要的效果。

如下图,虽然此时内存中共有3MB的空闲内存,但都不是连续的,因此其它进程只能申请到小于等于1MB的内存。

2.2 复制算法 

复制算法是对"标记清除"方式的优化,申请到内存之后,只使用内存的一半存储有效对象。出现有内存碎片时,就将有效对象归类到一起,也就是把有效对象拷贝到 存储有效对象的一半内存中,然后再将另一半内存进行释放。

复制算法能够防止出现内存碎片,但这个方式的内存利用率不高,且如果有效对象很多,拷贝的成本就很大了,效率太低。 

2.3  标记整理

标记整理 则是对 标记清除 和 复制算法 的优化,当内存中出现内存碎片时,则会将有效对象拷贝到空闲的内存中,将其覆盖,类似于顺序表删除元素的操作,这样就可以避免内存碎片了。但也涉及到了同样的问题,当需要拷贝的对象太多时,也会有很大的内存开销

2.4 分代回收

JVM在回收垃圾时,采用的方式一般就是 “分代回收”。此方法则是将堆区 划分为 两个区域,分别是"新生代""老年代"。"新生代"区域又划分为两个区域,分别是"伊甸区" 和 "幸存区",幸存区被划分为两块大小相同的区域。

刚创建出来的对象都会出现在"新生代"区域,“GC扫描线程” 会对 新生代区域的对象进行扫描。虽然从 对象的诞生 到 第一轮可达性分析扫描的过程 不会间隔较长时间,但在这段时间里,大部分对象都会成为"垃圾"。因为,这段时间对于程序而言,已经是挺长的时间了,在这个时间段中,对象的引用很快就会随着方法的执行完毕就销毁了,那么这些对象就会成为"垃圾"了。

经过一轮扫描之后,幸存下来的对象就会被拷贝到"幸存区"的一半区域中"伊甸区"的内存就可以整体释放了。虽然这个过程涉及到了拷贝对象的操作,但一般拷贝的对象并不多,因此内存开销是可承受的。GC扫描线程会在后续的扫描过程中,去扫描"幸存区"中的对象。如果幸存区中的对象经过一轮扫描后仍在存在,则会把这个对象拷贝到幸存区的另一半。在幸存区中,每经过一轮扫描,幸存下来的对象都会被拷贝到幸存区的另一半。幸存的对象在幸存区来回拷贝的过程中,会有许多对象被回收掉。如果经过多次扫描幸存区中的某些对象一直存在JVM则会把这些对象放在“老年代”中。相比于“新生代”,“老年代”区域的扫描频率要低,因为JVM认为“老年代”中的对象存活的时间较长。

将整个堆区划分为"新生代"和"老年代",也是为了降低GC扫描的开销。

分代回收则是通过上述的方式来进行垃圾回收,也是综合了 标记清除,复制算法,标记整理的优点,降低内存开销的同时,也避免了内存碎片。

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

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

相关文章

文心一言 VS 讯飞星火 VS chatgpt (250)-- 算法导论18.2 3题

三、请说明如何在一棵 B 树中找出最小关键字,以及如何找出某一给定关键字的前驱。如果要写代码,请用go语言。 文心一言: 在B树(也称为B-tree)中,最小的关键字总是位于最左边的叶子节点的最左边的元素。要…

C++ | 类和对象(中) (构造函数 | 析构函数 | 拷贝构造函数 | 赋值运算符重载 | 取地址 | const取地址)

目录 默认成员函数 构造函数 构造函数是什么 构造函数特征 什么是默认构造函数 注意事项 编译器自动生成的默认构造 缺省值 对象如何传值给构造函数 初始化列表 析构函数 析构函数的特征 编译器默认生成的析构函数 总结 拷贝构造函数 拷贝构造函数的使用场景 拷…

MySQL数据库练习(13)

schooldb库——utf8字符集——utf8_general_ci排序规则 61. DDL CREATE TABLE settlements (settlementId int(11) NOT NULL AUTO_INCREMENT COMMENT 自增ID,settlementNo varchar(20) NOT NULL COMMENT 结算单号,settlementType tinyint(4) NOT NULL DEFAULT 0 COMMENT 结算…

金融案例:统一查询方案助力数据治理与分析应用更高效、更安全

随着企业数据规模的增长和业务多元化发展,海量数据实时、多维地灵活查询变成业务常见诉求。同时多套数据库系统成为常态,这既带来了数据管理的复杂性,又加大了数据使用的难度,面对日益复杂的数据环境和严格的数据安全要求&#xf…

Centos7 安装Git、使用

Centos7 安装Git 一、安装步骤1.1 查看版本1.2 卸载1.3 安装 二、创建仓库2.1 新增仓库2.2 新增配置项 三、管理文件3.1 文件创建3.2 文件修改、add、commit3.3 tree结构探索 四、分支4.1 创建分支:4.2 查看分支4.3 切换分支4.4 删除分支4.5 合并冲突 一、安装步骤 …

【蓝桥杯嵌入式】第七届省赛 - 模拟液位检测告警系统

代码开源,Gitee自取 代码开源,Gitee自取 代码开源,Gitee自取 目录 0 前言 1 展示 1.1 源码 1.2 演示视频 1.3 题目展示 2 工程配置 3 资源配置&代码实现 3.1 定时器 3.2 液位检测 3.3 液位阈值设定 3.4 液位阈值设定 3.5 串…

使用unreal engine5.3.2创建c++第一人称游戏

UE5系列文章目录 文章目录 UE5系列文章目录前言一、NuGet 简介二、解决方法: 前言 为了使用unreal engine5.3.2创建c第一人称游戏,今天安装了Visual Studio 2022专业版。在ue5中创建c工程,结果编译器报错: 严重性 代码 说明 项目…

UDP和TCP(传输层)

这里写目录标题 UDPUDP的基本特点UDP协议报文格式 TCPTCP协议报文格式TCP特点可靠传输实现机制确认应答超时重传数据丢了应答报文丢了 小结 UDP UDP的基本特点 无连接不可靠传输面向数据报全双工 UDP协议报文格式 2个字节有效范围(无符号): 0 ~ 65535(2^16 - 1). 2个字节有效范…

Web开发:<div>作用

< div >元素作用 解释用途1. 布局&#xff1a;2. 样式化&#xff1a;3. 结构化&#xff1a;4. JavaScript操作&#xff1a;5. 响应式设计&#xff1a;6. 模块化和重用&#xff1a;7. 包裹其他元素&#xff1a;8. 清除浮动&#xff1a; 总结举例示例结果分析 解释 在Web开…

全栈开发之路——前端篇(1)介绍、框架确定、ide设置与项目创建

文章目录 前言一、前端框架React和VueReactVue 二、编译器选择和配置1.传统的下载和使用2.你可能遇到的问题1.ERR&#xff01; syscall mkdir2.vue : File C:\nodejs\node_global\vue.ps1 cannot be loaded because running scripts is disabled on3.出现乱码问题 3.运行Vue 三…

模型智能体开发之metagpt-单智能体实践

需求分析 根据诉求完成函数代码的编写&#xff0c;并实现测试case&#xff0c;输出代码 代码实现 定义写代码的action action是动作的逻辑抽象&#xff0c;通过将预设的prompt传入llm&#xff0c;来获取输出&#xff0c;并对输出进行格式化 具体的实现如下 定义prompt模版 …

python算法题

需求 代码 class Solution:def searchInsert(self, nums: List[int], target: int) -> int:if max(nums) >target:for i in range(len(nums)-1):if nums[i1] > target and nums[i] <target:return i1if max(nums) <target:return len(nums)if min(nums) > …

解析transformer中的各模块结构

transformer是一种编解码&#xff08;encoder-decoer&#xff09;结构&#xff0c;用于自然语言处理、计算机视觉等领域&#xff0c;编解码结构是当前大模型必包含的部分。 文章目录 1. 词嵌入模块 2.位置编码模块 3. 多头注意力机制模块 3.1 自注意力机制模块 3.2 多头注…

Golang图片验证码的使用

一、背景 最近在使用到Golang进行原生开发&#xff0c;注册和登录页面都涉及到图片验证码的功能。找了下第三方库的一些实现&#xff0c;发现了这个库用得还是蛮多的。并且支持很多类型的验证方式&#xff0c;例如支持数字类型、字母类型、音频验证码、中文验证码等等。 项目地…

操作系统(2)——进程线程

目录 小程一言专栏链接: [link](http://t.csdnimg.cn/8MJA9)基础概念线程详解进程详解进程间通信调度常用调度算法 重要问题哲学家进餐问题问题的描述策略 读者-写者问题问题的描述两种情况策略 总结进程线程一句话 小程一言 本操作系统专栏&#xff0c;是小程在学操作系统的过…

Dockerfile实战(SSH、Systemctl、Nginx、Tomcat)

目录 一、构建SSH镜像 1.1 dockerfile文件内容 1.2 生成镜像 1.3 启动容器并修改root密码 二、构建Systemctl镜像 2.1 编辑dockerfile文件 ​编辑2.2 生成镜像 2.3 启动容器&#xff0c;并挂载宿主机目录挂载到容器中&#xff0c;然后进行初始化 2.4 进入容器验证 三、…

考研管理类联考(专业代码199)数学基础【2】整式与分式

一、整式及其运算 1.常用乘法公式&#xff08;逆运算就是因式分解&#xff09; 公式扩展① 公式扩展② 公式扩展③ 2.整式除法定理 若整式 F(x) 除以x-a的余式为r(x)&#xff0c;则 F(x) (x -a) g(x) r(x) &#xff0c;故r(a)F(a)成立 二、指数和对数的运算性质 1.指数运算…

【电路笔记】-石英晶体振荡器

石英晶体振荡器 文章目录 石英晶体振荡器1、概述2、石英晶体等效模型3、石英晶体振荡器示例14、Colpitts 石英晶体振荡器5、Pierce振荡器6、CMOS晶体振荡器7、微处理器水晶石英钟8、石英晶体振荡器示例21、概述 任何振荡器最重要的特性之一是其频率稳定性,或者换句话说,其在…

Linux migrate_type初步探索

1、基础知识 我们都知道Linux内存组织管理结构架构&#xff0c;顶层是struct pglist_data&#xff0c;然后再到struct zone&#xff0c;最后是struct page。大概的管理结构是这样的&#xff1a; 根据物理内存的地址范围可划分不同的zone&#xff0c;每个zone里的内存由buddy…

审计师能力与专长数据集(2014-2022年)

01、数据介绍 审计师是专门从事审计工作的人员&#xff0c;他们对企业、政府机关、金融机构等组织进行独立的、客观的、合法的审计&#xff0c;以评估这些组织的财务状况、经营绩效和风险水平。审计师通过收集和评估证据&#xff0c;以确定被审计单位的财务报表是否公允、合法…