Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java 垃圾收集器的垃圾收集算法

Java 垃圾收集器的垃圾收集算法

作者头像
CS实验室
发布于 2021-03-22 04:26:18
发布于 2021-03-22 04:26:18
5230
举报
文章被收录于专栏:CS实验室CS实验室

垃圾收集器的垃圾收集算法

在之前曾分享了一篇 Junnplus 关于 Python 垃圾回收的文章,孟同学读后不服,立马撰文以表达对 Java 真挚的爱❤️。 各个语言的 GC 算法其实大同小异而且抄来抄去,对比着看也是一件有趣的事情。

在 Java 中,垃圾回收是个基础而有趣的话题,本文主要讲解 Java 垃圾收集器的垃圾收集算法,首先,需要理解几个概念:

引用计算法:通俗的讲,引用计数法是这样这样一种场景,在类中设置一个计数变量,专门用来存储当前类有多少引用,如果被某个类引用,变量 +1,如果不再引用,变量就 -1,变量为 0 的时候认为此类没有任何引用。这种方法会有一个缺陷:如果两个类互相引用,两个类的计数变量都不为 0,但是两个类应该被回收,因为计数变量大于 0,所以无法回收。三个对象 A,B,C,A 中引用了 B,B 中引用了 C,C 中引用了 A,这就成为了一个循环引用,四个对象,五个甚至更多,都可以构成循环引用,其实两个类也可以看作循环引用。

可达性:通俗来说,可达性分析就是从一个点是否能搜索到另一个点,例如中国版图,以水为界,以陆地为连接,北京为根节点,从北京出发,在陆地上能到达上海,新疆,西藏,但是海南和台湾,因为隔着琼州海峡和台湾海峡,与大陆不连通,这种场景被认为不可达(其实坐船,坐飞机都能到)。从根节点查找其他节点的过程可以理解为可达性分析,如果某个或某几个对象连通,但是没有和根节点连通,我们认为这个(些)对象不可达,这样能解决循环引用问题,根节点的话,问度娘吧。

标记清理算法

此算法就是字面上的意思,先是把内存中需要收集的对象标记下来,然后进行内存空间回收。

标记的方法可以使用可达性分析,不采用引用计数法。优点是算法简单,易于理解,缺点是标记和清理的效率都很低,而且这种方法会产生内存碎片。假设经过了一次内存回收,空间中剩余一共 10k 内存,最大的块能容纳6k大的对象,现在要申请 7k 内存,发现在内存中找不到能容下 7k 的块,于是要提前触发一次垃圾回收,不仅仅是浪费资源,效率也大大降低。

复制算法

为了解决效率问题,有人提出了复制算法:把内存空间分成相等的两份(内存大小比例为 1:1 ),暂且记作 A、B,用其中的一份用来内存分配,这里我们选 A,当触发回收操作的时候,把不回收的对象拷贝到另一块内存中,也就是把 A 中的拷贝到 B 中去,然后把 A 全部回收,这样,用来分配内存的那一块就变成了 B,B 中还有存活的对象,A 中被全部清空,下一次回收时,再把 B 中存活的对象拷贝到 A 中,然后全部回收 B。复制算法解决了效率低下的问题和内存碎片过多问题,但是把内存等分为 2 份,对内存实在是太浪费资源了。假设你买了台新笔记本,内存是 16G,但是只能用 8G,是不是很不爽?

分代思想(这不是算法): 根据一份IBM的专门调查报告,发现 98% 的对象都是“朝生夕死”,存活周期相当短(想想我们的方法中的变量),还有一些对象生命周期比较长,人们把存活周期比较短的分到新生代,把存活周期比较长的分到老年代。

标记整理

复制算法有很多缺点:当存活的对象较多,复制会花费很多的时间,效率低下,最致命的是会有50% 的空间不能使用。极端情况下,如果应该被回收的内存中对象 100% 存活,然后又有新的内存申请,我们不得不增加一块额外的空间来应对这种极端情况。老年代中的对象存活周期都比较长,有人在标记-清理算法的基础上,提出了标记-整理算法,这种算法先去标记需要回收的对象(这个和标记-清理算法的标记过程是一样的),然后将存活的对象往空间的一端移动,记录需要回收的对象和存活对象的界限,然后清理需要回收的内存区域。

分代收集

这并不是新的算法,而是根据新生代和老年代不同的存活周期,选择不同的算法,老年代采用标记-整理算法,而新生代采用复制算法,不过比例不是 1:1,而是 8:1:1,占 8/10 区域的是新生代,被称作 Eden,另外两块区域大小相同,被称作 Survivor1 和 Survivor2,内存回收时,把 Eden 和 Survivor1 中的存活对象拷贝到 Survivor2 中,回收 Eden 和 Survivor1 两个空间,下一次回收时,把 Eden 和 Survivor2 中的存活对象拷贝到 Survivor1 中,回收 Eden 和 Survivor2 两个空间,如此往复回收。因为 Eden 空间大,并且其中的对象会被回收 90% 以上,所以复制算法比较有优势。如果出现 Eden 和 Survivor(记为 Survivor) 中存活的对象比另一个 Survivor(记为 Survivor2) 空间大的情况,就会选择 Survivor1 中的经过多次回收还在存活的对象(这种对象被认为存活周期较长)进入老年代,释放出足够的空间,这种操作被称为分配担保,就像是银行贷款的担保人一样。需要存放存活对象的 Survivor 中内存空足够了,就进行 Eden 和 Survivor 的回收操作。

现在的主流虚拟机都采用分代收集算法,在新生代中,每次垃圾收集时都有大批对象死去,只有少量存活,适合采用复制算法,老年代中存活率高,而且没有额外的空间为它进行分配担保,适合采用标记-清理或标记-整理算法。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-07-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CS实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JVM中垃圾收集算法总结
  通过前面的介绍我们了解了对象创建和销毁的过程。那么JVM中垃圾收集器具体对对象回收采用的是什么算法呢?本文主要记录下JVM中垃圾收集的几种算法。
用户4919348
2019/04/02
4340
JVM中垃圾收集算法总结
深入理解Java虚拟机——JVM垃圾回收机制和垃圾收集器详解
说起垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来。在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,顾名思义,垃圾回收就是释放垃圾占用的空间,这一切都交给了JVM来处理。本文主要解答三个问题:
全栈程序员站长
2022/08/27
7400
深入理解Java虚拟机——JVM垃圾回收机制和垃圾收集器详解
JVM笔记-垃圾收集算法与垃圾收集器
引用计数法(Reference Counting):为每个对象添加一个引用计数器,用来统计指向该对象的引用个数。当有地方引用它时,计数器加一;引用失效时减一。当某个对象的引用计数为零时,说明该对象已死亡,便可以被回收了。
WriteOnRead
2020/02/24
5350
JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)
  按照套路是要先装装X,谈谈JVM垃圾回收的前世今生的。说起垃圾回收(GC),大部分人都把这项技术当做Java语言的伴生产物。事实上,GC的历史比Java久远,早在1960年Lisp这门语言中就使用了内存动态分配和垃圾回收技术。设计和优化C++这门语言的专家们要长点心啦~~
哲洛不闹
2019/03/11
1.4K0
JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)
GC算法和垃圾收集器
垃圾收集器在对堆回收之前,第一件事情就是要确定这些对象哪些还“存活”着,哪些对象已经“死去”(即不可能再被任何途径使用的对象)、
leobhao
2022/06/28
3910
GC算法和垃圾收集器
垃圾收集算法
在前面的引用计数法和可达性算法一文中,我们讲了一个引用要被回收需要达到的条件以及怎么判断一个引用是否要被回收。了解了这些知识,就到了今天要讲的垃圾收集算法。
飞翔的竹蜻蜓
2020/07/08
7150
垃圾收集算法
垃圾收集算法及细节
这是我们一贯认为的垃圾收集方式,在大多的商业虚拟机中几乎都遵循着分代收集的理论。分代收集理论建立在以下三个方面。
胖虎
2020/11/24
3220
垃圾收集算法及细节
JAVA 垃圾收集器与内存分配策略
垃圾收集技术并不是Java语言首创的,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言。垃圾收集技术需要考虑的三个问题是:
zhangheng
2020/04/28
5620
垃圾收集算法
思想: 标记清除算法分为“标记”和“清除”两个阶段:首先标记出需要回收的对象,在标记完成后统一回收所有被标记的对象,标记的方法就是可达性分析算法。
鳄鱼儿
2024/05/21
1150
垃圾收集算法
jvm的垃圾回收机制_垃圾回收厂
我们知道自动的垃圾回收机制是Java语言一个特点,它让我们在写程序的时候不再需要考虑内存管理问题。内存管理实际上就是分配内存和回收内存这两个问题,在上一篇文章我大概介绍了jvm是如何划分内存空间以合理的分配内存的,而这篇文章就介绍一下jvm是如何回收内存的。
全栈程序员站长
2022/09/23
5580
jvm的垃圾回收机制_垃圾回收厂
JVM的垃圾收集器策略
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
大大大大大先生
2018/09/04
3130
垃圾收集算法 Krains 2020-08-06
每个对象保存一个整型的引用计数器,假设有一个对象A,如果别的对象引用了A,就让A对象的引用计数器加1,如果引用失效了,计数器减1,当计数器为0的时候,该对象就是垃圾。
Krains
2020/08/10
3000
垃圾收集算法  Krains 2020-08-06
GC垃圾收集器之美
Java最早做了垃圾回收机制,也就是我们说的GC,jvm通过垃圾回收机器,也随着jdk版本的迭代,不断的再进步。
Joseph_青椒
2023/08/05
4850
GC垃圾收集器之美
垃圾收集策略与算法
程序计数器、虚拟机栈、本地方法栈随线程而生,也随线程而灭;栈帧随着方法的开始而入栈,随着方法的结束而出栈。这几个区域的内存分配和回收都具有确定性,在这几个区域内不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。
黑洞代码
2021/04/23
3560
面试官:你对JVM垃圾收集器了解吗?13连问你是否抗的住!
4、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
程序员追风
2020/05/15
2.7K0
面试官:你对JVM垃圾收集器了解吗?13连问你是否抗的住!
《深入理解java虚拟机》笔记(5)垃圾回收算法及垃圾收集器
算法:分为标记和清除两个阶段,首先标记出所有需要回收的对象,再对标记对象进行回收。
夕阳也是醉了
2023/10/16
1640
《深入理解java虚拟机》笔记(5)垃圾回收算法及垃圾收集器
JVM-05垃圾收集Garbage Collection(中)【垃圾收集算法】
JVM-04垃圾收集Garbage Collection(上)【垃圾对象的判定】探讨了如何判定堆内存中的对象是否已经死亡,这里我们来继续讨论下JVM中常用的垃圾收集算法
小小工匠
2021/08/17
2570
垃圾收集器与内存分配策略
该文介绍了Java中的垃圾收集器(Garbage Collector)和内存分配与回收策略,包括Serial、Parallel、CMS、G1等收集器以及堆内存的分配和回收策略,如对象优先在Eden分配、大对象直接进入老年代、长期存活的对象进入老年代等。
YGingko
2017/12/28
6730
垃圾收集器与内存分配策略
Java垃圾收集器总结
ZGC、G1和Shenandoah 都是以低延迟为主的收集器,总结了一下三者的区别
eeaters
2022/03/06
4690
Java垃圾收集器总结
垃圾收集器与内存分配策略
上面示例代码中有两段完全一样的代码片段,执行结果却是一次逃脱成功,一次失败了,这里任何一个finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法就不会再次执行。
程序员波特
2024/01/19
1960
垃圾收集器与内存分配策略
相关推荐
JVM中垃圾收集算法总结
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档