垃圾回收算法

垃圾回收的概念

垃圾回收(Garbage Collection,简称GC),顾名思义就是释放垃圾占用的空间,防止内存爆掉。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。

垃圾判断算法

既然JVM要做垃圾回收,就要搞清楚什么是垃圾,什么不是垃圾。通常会使用几种算法来判断一个对象是否是垃圾。

  • 引用计数算法
  • 可达性分析算法

引用计数算法

引用计数算法(Rebchability Counting)是通过在对象头中分配一个空间来保存该对象被引用的次数(Reference Count)。

如果该对象被其他对象引用,则它的引用计数加1;如果删除对该对象的引用,那么他的引用计数就减1。当该对象的引用计数为0时,那么该对象就会被回收。

String s = new String("芒克芒克");

举个栗子,我们来创建一个字符串,这时候“芒克芒克”,有一个引用,就是s。此时Reference Count = 1。

然后将s设置为null。

s = null;

这时候“芒克芒克”的引用次数就等于0了,在引用计数算法中,意味着这块内容就需要被回收了。

引用计数算法将垃圾回收分摊到整个应用程序的运行当中,而不是集中在垃圾收集时。

引用计数算法看起来很美好,但实际它存在一个很大的问题,那就是无法解决临时循环依赖的问题。来看以下代码。

public class ReferenceCountingGC { public Object instance; // 对象属性,用于存储对另一个 ReferenceCountingGC 对象的引用 public ReferenceCountingGC(String name) { // 构造方法 } public static void testGC() { // 创建两个 ReferenceCountingGC 对象 ReferenceCountingGC mk = new ReferenceCountingGC("芒克芒克"); ReferenceCountingGC km = new ReferenceCountingGC("克芒克芒"); // 使 a 和 b 相互引用 mk.instance = km; km.instance = mk; // 将 a 和 b 设置为 null mk = null; km = null; // 这个位置是垃圾回收的触发点 } }

上述代码中创建了两个ReferenceCountingGC对象mk和km。

然后将它们相互引用。接着,将这两个对象的引用设置为null,理论上它们会在接下来被垃圾回收器回收。但由于它们相互引用着对方,导致它们的引用计算永远都不会为0,通过引用计数算法,也就永远无法通知GC收集器回收它们。

可达性分析算法

可达性分析算法(Reachability Analysis)的基本思路是,通过GCRoots作为起点,然后向下搜索,搜索走过的路径被称为ReferenceChain(引用链),当一个对象到GCRoots之间没有任何引用相连时,即从GCRoots到该对象节点不可达,则证明该对象时需要垃圾手机的。

通过可达性算法,成功解决了引用计数无法解决的问题:“循环依赖”,只要你无法与GCRoot建立直接或间接的连接,系统就会判断你为可回收对象。

所谓的GCRoots,就是一组必须活跃的引用,不是对象,它们是程序运行的起点,是一切引用链的源头。在Java中,GCRoots包括以下几种:

  • 虚拟机栈中的引用(方法的参数、局部变量等)
  • 本地方法栈中JNI的引用
  • 类静态变量
  • 运行时常量池中的常量(String或Class类型)

StopTheWorld

Stop The World是Java垃圾收集中的一个重要概念。在垃圾收集过程中,JVM会暂停所有的用户线程,这种暂停被称为“Stop The World”事件。

这么做的主要原因是为了防止在垃圾收集过程中,用户线程修改了堆中的对象,导致垃圾收集器无法准确地收集垃圾。

值得注意的是,“Stop The World”事件会对Java应用的性能产生影响。如果停顿时间过长,就会导致应用的响应时间变长,对于对实时性要求较高的应用,如交易系统,游戏服务器等,这种情况是不能接受的。

因此,在选择和调优垃圾收集器时,需要考虑其停顿时间。Java中的一些垃圾收集器,如GI和ZGC,都会尽可能地减少了“Stop The World”的时间,通过并发的垃圾收集,提高应用的响应性能。

总的来说,“Stop The World”是Java垃圾收集中必须面对的一个挑战,其目标是在保证内存的有效利用和应用的响应性能之间找到一个平衡。

垃圾收集算法

在确定了哪些垃圾可以被回收后,垃圾收集器要做的事情就是进行垃圾回收,但是这里面涉及到一个问题是:如何高效地进行垃圾回收。由于JVM规范并没有对如何实现垃圾收集器做出明确的规定,因此各个厂商的虚拟机可以采用不同的方式来实现垃圾收集器。以下是常见的垃圾收集算法。

标记清除算法

标记清除算法(Mark-Sweep)是最基础的一种垃圾回收算法,它分为2部分,先把内存区域中这些对象进行标记,哪些属于可回收的标记出来(用前面提到的可达性分析法),然后把这些垃圾拎出来清理掉。

就像上图一样,清理掉的垃圾就变成可使用的空闲空间,等待被再次使用。逻辑清晰,并且也很好操作,但它存在一个很大的问题,那就是内存碎片。碎片太多可能会导致当程序运行过程中需要分配较大对象时,因无法找到足够的连续内存而不得不提前触发新一轮的垃圾收集。

复制算法

复制算法(Copying)是在标记清除算法上演化而来的,用于解决标记清除算法的内存碎片问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。

当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样就保证了内存的连续性,逻辑清晰,运行高效。

但复制算法也存在一个很明显的问题,合着我这 190 平的大四室,只能当 90 平米的小两室来居住?代价实在太高。

标记整理算法

标记整理算法(Mark-Compact),标记过程仍然与标记清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,再清理掉端边界以外的内存区域。

标记整理算法一方面在标记-清除算法上做了升级,解决了内存碎片的问题,也规避了复制算法只能利用一半内存区域的弊端。看起来很美好,但内存变动更频繁,需要整理所有存活对象的引用地址,在效率上比复制算法差很多。

分代收集算法

分代收集算法(Generational Collection)严格来说并不是一种思想或理论,而是融合上述 3 种基础的算法思想,而产生的针对不同情况所采用不同算法的一套组合拳。

根据对象存活周期的不同会将内存划分为几块,一般是把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。

在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。

老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记清理或者标记整理算法来进行回收。

新生代和老年代

堆(Heap)是 JVM 中最大的一块内存区域,也是垃圾收集器管理的主要区域。

堆主要分为 2 个区域,新生代与老年代,其中新生代又分 Eden 区和 Survivor 区,其中 Survivor 区又分 From 和 To 两个区。

Eden区

据 IBM 公司之前的研究表明,有将近 98% 的对象是朝生夕死,所以针对这一现状,大多数情况下,对象会在新生代 Eden 区中进行分配,当 Eden 区没有足够空间进行分配时,JVM 会发起一次 Minor GC,Minor GC 相比 Major GC 更频繁,回收速度也更快。

通过 Minor GC 之后,Eden 区中绝大部分对象会被回收,而那些无需回收的存活对象,将会进到 Survivor 的 From 区,如果 From 区不够,则直接进入 To 区。

Survivor区

Survivor 区相当于是 Eden 区和 Old 区的一个缓冲,类似于我们交通灯中的黄灯。

为啥需要Survivor区?

不就是新生代到老年代吗,直接 Eden 到 Old 不好了吗,为啥要这么复杂。

如果没有 Survivor 区,Eden 区每进行一次 Minor GC,存活的对象就会被送到老年代,老年代很快就会被填满。而有很多对象虽然一次 Minor GC 没有消灭,但其实也并不会蹦跶多久,或许第二次,第三次就需要被清除。

这时候移入老年区,很明显不是一个明智的决定。

所以,Survivor 的存在意义就是减少被送到老年代的对象,进而减少 Major GC 的发生。Survivor 的预筛选保证,只有经历 16 次 Minor GC 还能在新生代中存活的对象,才会被送到老年代。

Survivor为何分成两块?

设置两个 Survivor 区最大的好处就是解决内存碎片化,我们先假设一下,Survivor 只有一个区域会怎样。

Minor GC 执行后,Eden 区被清空,存活的对象放到了 Survivor 区,而之前 Survivor 区中的对象,可能也有一些是需要被清除的。那么问题来了,这时候我们怎么清除它们?

在这种场景下,我们只能标记清除,而我们知道标记清除最大的问题就是内存碎片,在新生代这种经常会消亡的区域,采用标记清除必然会让内存产生严重的碎片化。

但因为 Survivor 有 2 个区域,所以每次 Minor GC,会将之前 Eden 区和 From 区中的存活对象复制到 To 区域。第二次 Minor GC 时,From 与 To 职责互换,这时候会将 Eden 区和 To 区中的存活对象再复制到 From 区域,以此反复。

这种机制最大的好处就是,整个过程中,永远有一个 Survivor space 是空的,另一个非空的 Survivor space 是无碎片的。

那么,Survivor 为什么不分更多块呢?比方说分成三个、四个、五个?

显然,如果 Survivor 区再细分下去,每一块的空间就会比较小,容易导致 Survivor 区满,两块 Survivor 区可能是经过权衡之后的最佳方案。

Old区

老年代占据着 2/3 的堆内存空间,只有在 Major GC 的时候才会进行清理,每次 GC 都会触发“Stop-The-World”。内存越大,STW 的时间也越长,所以内存也不仅仅是越大就越好。

由于复制算法在对象存活率较高的老年代会进行很多次的复制操作,效率很低,所以老年代这里采用的是标记整理算法。

除了上述所说,在内存担保机制下,无法安置的对象会直接进到老年代,以下几种情况也会进入老年代。

大对象

大对象指需要大量连续内存空间的对象,这部分对象不管是不是“朝生夕死”,都会直接进到老年代。这样做主要是为了避免在 Eden 区及 2 个 Survivor 区之间发生大量的内存复制。当你的系统有非常多“朝生夕死”的大对象时,得注意了。

长期存活对象

虚拟机给每个对象定义了一个对象年龄(Age)计数器。正常情况下对象会不断的在 Survivor 的 From 区与 To 区之间移动,对象在 Survivor 区中每经历一次 Minor GC,年龄就增加 1 岁。当年龄增加到 15 岁时,这时候就会被转移到老年代。当然,这里的 15,JVM 也支持进行特殊设置-XX:MaxTenuringThreshold=10

可通过java -XX:+PrintFlagsFinal -version | grep MaxTenuringThreshold查看默认的阈值。

动态对象年龄

JVM 并不强制要求对象年龄必须到 15 岁才会放入老年区,如果 Survivor 空间中某个年龄段及以上的对象总大小超过了 Survivor 空间的一半,那么该年龄段及以上年龄段的所有对象都会在下一次垃圾回收时被晋升到老年代,无需等你“成年”。

有点类似于负载均衡,轮询是负载均衡的一种,保证每台机器都分得同样的请求。看似很均衡,但每台机器的硬件不同,健康状况不同,所以我们可以基于每台机器接收的请求数、响应时间等,来调整负载均衡算法。

这种动态调整机制有助于优化内存使用和减少垃圾收集的频率,特别是在处理大量短生命周期对象的应用程序时。

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

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

相关文章

一张图理清网络安全核心框架:体系、模型与标准体系的演进之路

网络安全体系概述 4.1.1 网络安全体系概述 一般面言,网络安全体系是网络安全保障系统的最高层概念抽象,是由各种网络安全单元按照一定的规则组成的,共同实现网络安全的目标。网络安全体系包括法律法规政策文件、安全策略、组织管理、技术措…

网络安全防护实战指南:关键技术演进与现代企业级解决方案

1:网络基础知识 Internet通过TCP/IP协议将遍布在全世界各地的计算机互联,从而形成超大的计算机网络。 2: 3:网络协议层模型 4:通信网络地址的发出点为源地址,接收点为目的地址; 在通信网络中&…

慢思考,深搜索:MiroThinker 1.5 如何重塑 AI 研究智能体范式

前言过去两年,AI 的主流叙事始终围绕“更快、更强、更聪明”展开。大模型竞相堆叠参数,响应速度被压缩到毫秒级,对话流畅度几乎以假乱真。这种进化路径在日常问答、内容生成等场景中确实带来了显著体验提升。但当我们面对需要深度调研、逻辑推…

一文读懂探针卡的概念、组成、分类以及应用

探针卡(Probe Card)在集成电路测试中起着至关重要的作用,尤其在晶圆测试(wafer test)环节,探针卡作为连接ATE测试机台和半导体晶圆之间的接口,确保了在芯片封装前对其电学性能进行初步测量和筛选…

从入门到精通:网络安全核心技术栈详解与实践路线图

网络安全技术虽然非常复杂,但是归纳起来,主要就是为了解决以下三方面问题: 1.数据的机密性:即如何令人们发送数据,即使被其他无关人员截取,他们也无法获知数据的含义。 2.数据的有效性:指数据不…

探讨 ‘Memory-augmented Retrieval’:利用历史对话的 Checkpoint 作为查询权重,提升检索的相关性

尊敬的各位同仁,欢迎来到本次关于“Memory-augmented Retrieval”的讲座。今天我们将深入探讨如何利用历史对话的“Checkpoint”作为查询权重,显著提升检索系统的相关性,尤其是在多轮对话和复杂交互场景中。在当今的AI时代,检索增…

论文降aigc保姆级教程:手把手教你免费降ai率,告别高ai焦虑。

最近太多人私信我:“论文AI率太高怎么办?连人工改的都不过检测!” 这事儿我太懂了——前段时间我自己也被AI检测折磨得快崩溃。 市面上一堆打着“降低AI率”旗号的网站,不是乱扣格式,就是改完反而更像AI写的。 所以我…

腾讯云VOD AIGC视频生成工具 回调实现

腾讯云VOD AIGC视频生成工具 一个功能完整的腾讯云VOD AIGC视频生成工具库,支持轮询模式和回调模式两种获取结果方式。 目录结构 test/vod/ ├── tencent_aigc_video.py # 核心库:API封装、任务管理 ├── config.py # 配置文件&a…

基于yolov11实现车辆速度估计+距离测量+轨迹跟踪+区域进出统计python源码实现

这个是网上目前可能唯一一个使用不足一百行代码实现了复杂车辆速度估计距离测量轨迹跟踪区域进出统计系统。之所以这么简单是因为ultralytics模块现在已经成熟而且强大,不需要从头开始写车辆速度估计、距离测量、轨迹跟踪、区域进出统计系统代码,因为里面…

PCB阻焊层与助焊层的本质区别

清晰理解PCB的“化妆术”:阻焊层与助焊层的本质区别在Altium Designer(AD)中设计PCB时,我们经常在层叠管理器里看到 Solder Mask 和 Paste Mask 这两层。它们到底是什么?为什么总是成对出现?简单来说&#…

架构师视角:网络安全体系深度解析——核心模型、数据标准与落地实践

网络安全体系概述 4.1.1 网络安全体系概述 一般面言,网络安全体系是网络安全保障系统的最高层概念抽象,是由各种网络安全单元按照一定的规则组成的,共同实现网络安全的目标。网络安全体系包括法律法规政策文件、安全策略、组织管理、技术措…

本章节我们将讨论如何在 React 中使用表单。

React 表单与事件 本章节我们将讨论如何在 React 中使用表单。HTML 表单元素与 React 中的其他 DOM 元素有所不同,因为表单元素生来就保留一些内部状态。在 HTML 当中&#xff0c;像 <input>, <textarea>, 和 <select> 这类表单元素会维持自身状态&#xff0…

专利解析:涂液器凸轮槽与导向突起的滑动配合机制

在追求健康头皮与浓密秀发的道路上&#xff0c;一款得心应手的头皮护理液涂抹工具至关重要。今天我们要探讨的这款液体化学药剂涂抹器&#xff0c;专为涂抹头皮护理液而设计&#xff0c;旨在促进头皮健康、预防脱发。有了它&#xff0c;用户只需轻轻倾斜&#xff0c;就能将护理…

Escrcpy(安卓手机投屏软件)

Escrcpy 是一款强大的工具&#xff0c;它允许用户通过图形化的 Scrcpy 界面来显示和控制他们的 Android 设备。这款应用程序由 Electron 作为其底层框架驱动。Escrcpy 无需任何账户就可以使用&#xff0c;无需担心隐私或安全问题。Escrcpy没有广告&#xff0c;完全免费开源。 软…

显微观察:Bamtone K系列盲孔显微镜性能优势深度评测

随着电子产品向着高密度、小型化的方向持续演进&#xff0c;印刷电路板&#xff08;PCB&#xff09;的制造工艺复杂度也随之攀升。高密度互连&#xff08;HDI&#xff09;技术中&#xff0c;盲孔&#xff08;Blind Via&#xff09;作为连接不同层电路的关键结构&#xff0c;其质…

Photo Editor安卓版(照片编辑器安卓版)

Photo Editor是一款功能强大的图像编辑工具&#xff0c;适用于安卓设备。它提供了丰富的编辑功能&#xff0c;可以帮助您对照片进行各种调整、修饰和美化。不论您是想增强照片的颜色、裁剪图像的尺寸、添加滤镜效果&#xff0c;还是修复照片中的缺陷&#xff0c;这款软件都能满…

利用多智能体AI实现动态竞争格局评估

利用多智能体AI实现动态竞争格局评估关键词&#xff1a;多智能体AI、动态竞争格局评估、智能体交互、机器学习、博弈论摘要&#xff1a;本文聚焦于利用多智能体AI实现动态竞争格局评估这一重要课题。首先介绍了该研究的背景、目的、预期读者等内容。接着详细阐述了多智能体AI和…

【高斯泼溅】当3DGS遇上传统模型:从“画在一起”到“画得对”的全攻略​

在真实场景重建、数字孪生与新一代三维表达体系中&#xff0c;3DGS正迅速成为不可忽视的技术方向。凭借在细节保真度、重建效率和真实感上的优势&#xff0c;它让传统基于三维精模、倾斜摄影和网格建模的表达方式&#xff0c;首次在“真实还原”层面显得力不从心。 城市场景-3D…

leetcode 856. Score of Parentheses 括号的分数-耗时100

Problem: 856. Score of Parentheses 括号的分数 解题过程 耗时100%&#xff0c;两种方案的&#xff0c;1、递归调用即可&#xff0c;2、或者使用栈的&#xff0c; 1、使用栈&#xff0c;耗时100% int scoreOfParentheses(string s) {if(s"()") return 1;int n s.si…

aigc免费降重神器测评:这才是降低ai率的正确打开方式,降ai率必看。

最近太多人私信我&#xff1a;“论文AI率太高怎么办&#xff1f;连人工改的都不过检测&#xff01;” 这事儿我太懂了——前段时间我自己也被AI检测折磨得快崩溃。 市面上一堆打着“降低AI率”旗号的网站&#xff0c;不是乱扣格式&#xff0c;就是改完反而更像AI写的。 所以我…