详解垃圾回收算法,优缺点是什么?|金三银四系列
本文详细介绍了在 JVM 中如何判断哪些对象是需要回收的,以及不同的垃圾回收算法以及优缺点。
点击上方“后端开发技术”,选择“设为星标” ,优质资源及时送达
上篇文章详细介绍了 JVM 的结构以及其内存结构,需要阅读请移步。本文主要讲解 JVM 体系中的垃圾收集子系统用到的内存回收算法。
八股文总是忘?一张图牢记JVM内存结构|金三银四系列
2023-02-13
哪些对象需要回收
在进行垃圾回收之前,第一件事就是确定哪些对象还存活着,哪些对象已死需要被回收。
1.引用计数算法
很多判断对象是否存活的算法是这样的:
给对象中添加一个引用计数器,每当有个地方引用它时,计数器值就加1;
当引用失效时,计数器值就减1,任何时刻计数器为0的对象就是不可能再被使用的,该对象将被回收。
客观的说,引用计数法实现简单,效率高。但是没有主流JVM选择引用计数法管理内存,因为他无法解决循环引用的问题。如下图
当三个对象都不在使用时,因为相互的引用关系,并不会置为0,所以难以被回收。并且,引用计数器要求在每次因引用产生和消除的时候,伴随一个加法操作和减法操作,对系统性能会有一定的影响。
2.可达性分析算法
主流JVM都是称通过可达性分析来判定对象是否存活的。这个算法的基本思路就是通过一系列的称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链( Reference Chain),当一个对象到GC Roots 没有任何引用链相连,用图论的话来说,就是从GC Roots 到这个对象不可达) 时,则证明此对象是不可用的。
如图所示,深灰色的对象虽然互相有关联,但是它们到 GC Roots 是不可达的,所以它们将会被判定为是可回收的对象。
GC Root 对象
Java中,有一组GC Roots对象,它们是被垃圾回收器直接管理的对象。GC Roots对象是垃圾回收的起始点,垃圾回收器会从这些对象开始遍历所有的对象,并标记出所有存活的对象,未被标记的对象即为可回收对象。
在Java中,可以作为GC Root对象的包括以下几类:
虚拟机栈(栈帧中的本地变量表)中引用的对象。虚拟机栈中保存着每个线程执行方法时的现场信息,包括局部变量、操作数栈、方法出口等。栈帧中的本地变量表中存放着方法中定义的局部变量和参数,如果局部变量或参数中引用了某个对象,则该对象被认为是一个GC Root对象。
方法区中类静态属性引用的对象。类似于栈帧中的本地变量表,类中定义的静态属性也会保存引用对象。因为静态属性是属于类的,所以这些引用对象也被认为是GC Root对象。
方法区中常量引用的对象。常量池中保存着编译器生成的各种字面量和符号引用,例如字符串常量、类和接口的全限定名、字段和方法的名称和描述符等。如果常量池中引用了某个对象,则该对象被认为是GC Root对象。
本地方法栈中JNI(即Java Native Interface)引用的对象。JNI是Java提供的一种机制,用于调用本地的C/C++代码。如果JNI中引用了某个对象,则该对象被认为是GC Root对象。
需要注意的是,不是所有的对象都可以作为GC Root对象。例如,普通的对象实例和数组元素就不可以作为GC Root对象。只有与Java虚拟机内存管理有关的对象才可以作为GC Root对象,因为它们直接或间接地引用了所有其他对象。
垃圾回收算法
1.标记-清除算法
最基础的收集算法是标记-清除算法(Mark-Sweep),如同它的名字一样,算法分为“标记”和“清除”两个阶段:
首先标记出所有需要回收的对象(可达性分析)。
在标记完成后统一回收所有被标记的对象。
之所以说它是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其不足进行改进而得到的。
优点
实现简单,算法简单、容易实现,与保守式GC 算法兼容,有效处理不连续的内存空间
不需要移动对象,因此不会浪费时间和空间。
不足
效率问题:标记和清除两个过程的效率都不高,且需要进行两次扫描,第一次标记垃圾对象,第二次清除垃圾对象。
空间问题:标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作,从而导致频繁的内存分配和回收。
2.标记-压缩算法(标记-整理)
标记压缩算法(Mark-Compact)是一种垃圾回收算法,主要用于老年代的垃圾回收。它的基本思想是在标记出所有存活对象之后,将所有存活的对象压缩到内存的一端,将所有空闲的内存空间释放出来,从而减少内存的碎片化。
标记压缩算法与标记-清除算法的区别在于,标记-清除算法只是标记出存活和垃圾对象,并将垃圾对象空间释放出来,因此容易造成内存的碎片化。而标记压缩算法则是将存活对象压缩到一端,并将空闲的内存空间释放出来,解决了内存碎片的问题。
标记压缩过程
标记压缩算法的具体实现过程如下:
标记阶段:从一组 GC Roots 开始,标记出所有存活的对象,并将这些存活对象的标记信息保存在对象头中。
压缩阶段:将所有存活的对象移动到内存的一端,释放出所有空闲的内存空间。在移动对象时,需要更新所有引用对象的指针,确保它们指向对象移动后的位置。
更新指针:由于移动对象的过程中,可能会修改引用对象的指针,因此需要扫描整个堆内存,将所有指向移动过的对象的指针进行更新。(这不算一个阶段)
由于需要更新所有引用对象的指针,因此在多线程情况下,需要使用屏障技术来确保线程安全性。
优点
可以有效地处理不连续的内存空间。
不会产生内存碎片,因为所有存活的对象都被移动到一端。
缺点
压缩阶段需要移动存活的对象,占用了系统的消耗,并且如果标记对象过多的话,损耗可能会很大,会浪费时间和空间。在标记对象相对较少的时候,效率较高。
需要进行两次扫描,第一次标记存活对象,第二次移动存活对象。
为什么没有清除阶段
标记-整理算法确实只有标记和整理两个阶段,没有显式的清除阶段。在整理阶段,垃圾回收器会将所有存活的对象向一端移动,将空间释放到另一端,这样空间的连续段就被重建了。因此,整理阶段的同时也具有清除的功能,所有未被移动的对象都是垃圾,可以直接被视为已经清除了。不过,在实现时,标记-整理算法的整理阶段可能需要把清除的操作分散在整个过程中进行,因此整理阶段通常会和清除阶段结合在一起,实现起来会更加高效。但是从逻辑上来说,标记-整理算法只需要标记和整理两个阶段,没有显式的清除阶段。
复制算法
为了解决效率问题,一种称为“复制”(Copying) 的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存话着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效,算是用空间来换时间的思维。
优点
可以有效地处理大部分对象都是临时对象的情况,例如新生代中的对象。
不会产生内存碎片,因为所有存活的对象都被复制到一个新的内存空间中。
缺点
需要一半的内存空间用于复制存活的对象,会造成空间浪费。
当有大量存活的对象时,复制效率会降低。
4.分代收集算法
目前主流JVM垃圾收集都采用“分代收集”(Generational Collection) 算法,这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保(如果有空间,通过分配担保机制进入老年代),就必须使用“标记一清理”或者“标记一整理”算法来进行回收。
对于新生代和老年代来说,通常新生代回收的频率很高,但是每次回收的时间都很短,而老年代回收的频率比较低,但是被消耗很多的时间。为了支持高频率的新生代回收,虚拟机可能使用一种叫做卡表(Card table)的数据结构,卡表为一个比特位集合,每一个比特位可以用来表示老年代的某一区域中的所有对象是否持有新生代对象的引用。
这样以来,新生代GC时,可以不用花大量时间扫描所有老年代对象,来确定每一个对象的引用关系,而可以先扫描卡表,只有当卡表的标记为1时,才需要扫描给定区域的老年代对象,而卡表为0的所在区域的老年代对象,一定不含有新生代对象的引用。
卡表中每一位表示老年代4KB的空间,卡表记录为0的老年代区域没有任何对象指向新生代,只有卡表为1的区域才有对象包含新生代对象的引用,因此在新生代GC时,只需要扫面卡表为1所在的老年代空间,使用这种方式,可以大大加快新生代的回收速度。
优点
根据对象的生命周期,将堆分为多个区域,使不同区域采用不同的回收算法,可以提高回收效率。
可以避免全局垃圾回收的情况,从而减少了暂停时间。
缺点
需要维护多个堆区域,增加了复杂性。可能会出现对象晋升的情况,导致老年代的内存压力增大。
5.分区算法
分代算法将按照对象的生命周期长短划分成两个部分,分区算法将整个堆空间划分成不同连续的区域。每个小区间都独立使用,采用不同的垃圾回收算法,独立回收。例如,可以将新生代分成多个区域,每个区域采用不同的复制算法,而老年代则采用标记-整理或标记-清除算法。这种算法的好处是可以控制一次回收多少个小区间。
一般来说,在相同的条件下,堆空间越大,一次GC时所需要的时间就越长,从而产生的停顿也越长。为了更好地控制GC产生的停顿时间,将一块大的内存区域分割为多个小块,根据目标的停顿时间,每次合理的回收若干个小区间,而不是整个堆空间,从而减少一次GC所产生的停顿。这算是一种分治思路。
最后,欢迎大家提问和交流。
如果对你有帮助,欢迎点赞、评论或分享,感谢阅读!
无需注册直接体验ChatGPT!附注册ChatGPT详细教程
2023-02-14
一文掌握,单机Redis、哨兵和Redis Cluster的搭建,建议收藏
2023-02-11
Dubbo重点,SPI的自适应扩展原理|原创
2023-01-11
相关文章:
详解垃圾回收算法,优缺点是什么?|金三银四系列
本文详细介绍了在 JVM 中如何判断哪些对象是需要回收的,以及不同的垃圾回收算法以及优缺点。点击上方“后端开发技术”,选择“设为星标” ,优质资源及时送达上篇文章详细介绍了 JVM 的结构以及其内存结构,需要阅读请移步。本文主要…...
Android 虚拟 A/B 详解(七) SnapshotManager 之标识文件
本文为洛奇看世界(guyongqiangx)原创,转载请注明出处。 原文链接:https://blog.csdn.net/guyongqiangx/article/details/129098176 Android 虚拟 A/B 分区《Android 虚拟 A/B 分区》系列,更新中,文章列表: Android 虚拟 A/B 详解(一) 参考资料推荐Android 虚拟 A/B 详解(二…...
LA@生成子空间@范数@衡量矩阵大小@正交化
文章目录线性组合与线性方程组生成子空间范数LpL^pLp范数向量点积用范数表示ref衡量矩阵大小特殊类型矩阵和向量对角阵向量长度性质单位向量向量单位化(正规化)正交向量正交正交向量组标准正交基正交化(schmidt)正交矩阵矩阵是正交矩阵的充要条件对称矩阵正交相似概念区分&…...
MT2012_竹鼠的白色季节
竹鼠的白色季节 #include<bits/stdc.h> #include<algorithm> using namespace std;/*思路:从小到大排序,然后依次往后遍历即可*/ int main( ) {int n,d;cin>>n>>d; int tmp;vector<int>nums;for(int i0;i<n;i){cin&…...
MySQL是什么?它有什么优势?
随着时间的推移,开源数据库在中低端应用中逐渐流行起来,占据了很大的市场份额。开源数据库具有免费使用、配置简单、稳定性好、性能优良等特点,而 MySQL 数据库正是开源数据库中的杰出代表。 开源全称为“开放源代码”。很多人认为开源软件最…...
基础篇—CSS padding(填充\内边距)解析
CSS padding(填充) CSS padding(填充)是一个简写属性,定义元素边框与元素内容之间的空间,即上下左右的内边距。 属性说明padding使用简写属性设置在一个声明中的所有填充属性padding-bottom设置元素的底部填充padding-left设置元素的左部填充padding-right设置元素的右部…...
二进制枚举
一、左移:用来将一个数的各二进制位全部左移n位,低位以0补充,高位越界后舍弃。n左移1位,n<<1,相当于2*n1左移n位,1<<n,相当于2^n二、右移:将一个数的各二进制位右移N位&…...
2|数据挖掘|聚类分析|k-means/k-均值算法
k-means算法k-means算法,也被称为k-平均或k-均值,是一种得到最广泛应用的聚类算法。算法首先随机选择k个对象,每个对象初始地代表了一个簇的平均值或中心。对剩余的每个对象根据其与各个簇中心的距离,将它赋给最近的簇。然后重新计…...
使用和制作动、静态库
文章目录什么是库?静态库打包方式使用方式生成并执行可执行程序粗暴方式优化方式动态库不一样的.o文件打包方式使用方式生成可执行程序运行可执行程序无法运行时的解决方案动静态库与动静态链接什么是库? 从一开始的helloworld,到现在熟练使…...
【Java基础】023 -- 集合进阶(List、Set、泛型、树)
目录 一、集合的体系结构 1、单列集合(Collection) 二、Collection集合 1、Collection常见方法 ①、代码实现: ②、contains方法重写equals方法示例:(idea可自动重写) 2、Collection的遍历方式(…...
面试题整理01-集合详解
文章目录前言一、集合的整体结构单列集合接口:双列集合接口:二、单列集合详解1.List接口1.1 ArrayList集合特点:扩容:添加元素遍历1.2 LinkedList集合特点:添加元素:2.Set接口2.1 HashSet集合特点ÿ…...
数据驱动的两阶段分布鲁棒(1-范数和∞-范数约束)的电热综合能源系统研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
ArcGIS网络分析之发布网络分析服务(二)
在上一篇中讲述了如何构建网络分析数据集,本篇将讲解如何发布网络分析服务。本文将使用上一篇中建立的网络数据集,下载地址在上一篇博文的最后已给出。 之前我们已经实现了基于ArcMap中的网络分析,但是仅仅支持本地是万万不够的,这里我们的目的就是将我们建好的网络分析图…...
js实现元素样式切换的基本功能
需求:用户第一次点击某些元素,改变元素的某些样式,比如背景颜色,字体颜色。用户第二次点击某些元素,恢复之前的样式。.....思路:准备一定量的div盒子,并取相同的类名<div class"box&quo…...
java 策略模式 + 工厂模式 实例
一 前言 经常听说各种设计模式,知道理论,也知道应该使用,但具体怎么用,什么时候用,使用的优点一直比较模糊,今天写一个项目中经常用到的模式,来具体理解。项目中经常用到工厂模式或者策略模式&…...
本地生成动漫风格 AI 绘画 图像|Stable Diffusion WebUI 的安装和部署教程
Stable Diffusion WebUI 的安装和部署教程1. 简介2. Windows安装环境3. 运行4. 模型下载链接5. 其他资源1. 简介 先放一张WebUI的图片生成效果图,以给大家学习的动力 :) 怎么样,有没有小小的心动?这里再补充一下&…...
华为OD机试 - 异常的打卡记录 | 备考思路,刷题要点,答疑 【新解法】
最近更新的博客 【新解法】华为OD机试 - 关联子串 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 停车场最大距离 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 任务调度 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试…...
「机器学习笔记」之深度学习基础概念(基于Pytorch)
本文以 Pytorch 为线索,介绍人工智能和深度学习相关的一些术语、概念。 关于发展历史您也可以阅读深度学习神经网络之父 Jrgen Schmidhuber 所写的《Annotated History of Modern AI and Deep Learning(现代人工智能和深度学习的注释版历史)…...
概率和似然
在日常生活中,我们经常使用这些术语。但是在统计学和机器学习上下文中使用时,有一个本质的区别。本文将用理论和例子来解释概率和似然之间的关键区别。 概率与似然 假设在一场棒球比赛中,两队的队长都被召集到场上掷硬币。获胜的队长将根据掷…...
前期软件项目评估偏差,如何有效处理?
1、重新评估制定延期计划 需要对项目进行重新评估,将新的评估方案提交项目干系人会议,开会协商一致后按照新的讨论结果制定计划,并实施执行。 软件项目评估偏差 怎么办:重新评估制定延期计划2、申请加资源 如果项目客户要求严格&a…...
Xline v0.2.0: 一个用于元数据管理的分布式KV存储
Xline是什么?我们为什么要做Xline? Xline是一个基于Curp协议的,用于管理元数据的分布式KV存储。现有的分布式KV存储大多采用Raft共识协议,需要两次RTT才能完成一次请求。当部署在单个数据中心时,节点之间的延迟较低&a…...
CompletableFuture
一、一个示例回顾Future 一些业务场景我们需要使用多线程异步执行任务,加快任务执行速度。JDK5新增了Future接口,用于描述一个异步计算的结果。虽然Future以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,我们必须使用Future.get()的方式阻塞调…...
面试不到10分钟就被赶出来了,问的实在是太变态了...
干了两年外包,本来想出来正儿八经找个互联网公司上班,没想到算法死在另一家厂子。 自从加入这家外包公司,每天都在加班,钱倒是给的不少,所以也就忍了。没想到11月一纸通知,所有人不许加班,薪资…...
【C++】类与对象 (四)初始化列表 static成员 友元 内部类 匿名对象 拷贝对象时的一些编译器优化
前言 本章就是我们C中类与对象的终章了,不过本章的难度不大,都是类中一些边边角角的知识,记忆理解就行了,相信经过这么长时间的学习类与对象,你对面向对象也有了更加深的理解,最后我们学习完边边角角的一些…...
04:进阶篇 - 编译 CTK
作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 在使用 CTK 之前,首先要进行编译。但要成功编译它,并不是一件很容易的事,这不仅取决于平台、Qt 的版本,也取决于编译器,以及所使用的 IDE。 平台(Linux、Windows)Qt 版本(4.x、5.x、6.x)编译器(MS…...
SQL73 返回所有价格在 3美元到 6美元之间的产品的名称和价格
描述有表Productsprod_idprod_nameprod_pricea0011egg3a0019sockets4b0019coffee15【问题】编写 SQL 语句,返回所有价格在 3美元到 6美元之间的产品的名称(prod_name)和价格(prod_price),使用 AND操作符&am…...
【Linux 多线程互斥】如何保证锁的原子性(互斥的原理)
临界资源:可以被多个执行流(线程或者叫轻量级进程)同是访问的(多个执行流共享的,比如:全局、堆等等);临界区:访问这些临界资源的代码;原子性:没有中间态&…...
Android 实现沉浸式全屏
前言 本文总结 Android 实现沉浸式全屏的实现方式。 实现沉浸式全屏 在一些需要全屏显示的场景下,比如玩游戏、看横屏视频的时候,内容全屏,占满窗口的体验会让用户更加沉浸到对内容的消费中,带来好的用户体验。 沉浸式显示具体来说就是如状态栏和导航栏部分的显示效果调…...
数据分析与SAS学习笔记6
数据集整理: 目的:对数据集中的数据进行预处理,使数据更适合统计分析过程对数据格式的要求; 常见整理要求: 1)建立新的变量,衍生变量,删除某些原变量; 2)…...
自动化完成1000个用户的登录并获取token并生成tokens.txt文件
自动化完成1000个用户的登录并获取token并生成tokens.txt文件 写作背景 在我学习使用redis实现秒杀功能的过程中,在编写完秒杀代码后,需要使用Jmeter实际测试1000个用户进行秒杀,由于秒杀功能需要在用户登录完成后才能实现,用户是…...
做外贸哪个网站可以接单/网址收录平台
1、下载bootstrap https://getbootstrap.com/docs/4.3/getting-started/download/ 2、在项目目录下创建static文件夹,将下载的bootstrap解压到该static下 3、新建html,layout.html,url_for引用bootstrap.css 这里的block为定义模块 <!DOCTYPE html…...
wordpress获取登录密码/网络营销策划方案框架
pig是hadoop的一个子项目,用于简化MapReduce的开发工作,可以用更人性化的脚本方式分析数据。 一、安装 a) 下载 从官网http://pig.apache.org下载最新版本(目前是0.14.0版本),最新版本可以兼容hadop 0.x /1.x / 2.x版本,直接解压到…...
wordpress+最新版本/北京网站seo招聘
题目解决代码及点评 /************************************************************************/ /* 15. 有 N个国家名,要求按字母先后顺序排列(用起泡排序法)后输出*/ /***************************…...
合肥网站建设制作价格/图床外链生成工具
中国质量新闻网2006年的一篇报道,1把失准钢卷尺,导致损失数10万元钱。计量器具是保障建筑工程质量的一个重要因素,只有加强计量工作,才是对人民生命财产的最大负责。 在工业产品的生产中,一件不合格的量具能使成批产品…...
太原商城网站建设/网络营销策划书的结构是什么
随时随地阅读更多技术实战干货,获取项目源码、学习资料,请关注源代码社区公众号(ydmsq666) 我们都知道Node.js现在得到了所有的关注。每个人都对学习Node.js感兴趣,并希望可以工作于Node.js。在开始工作之前了解技术背后的概念总是不会错的。…...
wordpress修改html/有哪些免费推广网站
Class对象是没办法用new关键字得到的,因为它是jvm生成用来保存对应类的信息的,换句话说,当我们定义好一个类文件并编译成.class字节码后,编译器同时为我们创建了一个Class对象并将它保存.class文件中。我不知道这样描述是否妥当,因…...