【从零开始学习JVM | 第八篇】学习垃圾回收算法 和 垃圾回收器

前言:

现代编程语言通常采用垃圾回收机制来自动管理内存。垃圾回收机制是一种自动化的内存管理技术,可以在程序运行时自动识别和回收不再使用的内存,从而减少内存泄漏和其他内存相关问题的发生。

本文将介绍垃圾回收算法垃圾回收器的相关知识,帮助读者深入了解内存管理的实现原理和技术细节。

目录

前言:

常见的垃圾回收算法:

1.标记-清除算法(Mark  Sweep GC)

2.复制算法(Copying GC)

3.标记整理算法(Mark  Compact GC)

4.分代GC(Generational GC)

年轻代: 

 老年代:

 分代GC的垃圾回收流程:

总结: 

 


 

垃圾回收的要做的事就两件:

1.找到内存中存活的对象,并进行分类

2.回收分类后需要被回收的对象

而所有的垃圾回收算法,都是围绕着这两步走的,我们一起来学习一下常见的垃圾回收算法:

常见的垃圾回收算法:

1.标记-清除算法(Mark  Sweep GC)

  1. 标记阶段:

    • 从根对象(如全局变量、活动线程的栈)开始,遍历对象图,并将可达的对象进行标记。这些可达对象被认为是活动对象,需要保留在堆内存中。
    • 通过遍历每个已标记对象的引用,递归地标记所有可达对象,直到无法继续标记为止。这样,所有的活动对象都会被标记为活动状态。
  2. 清除阶段:

    • 遍历整个堆内存,对于未被标记的对象,将其认定为垃圾对象。
    • 清除垃圾对象所占用的内存空间,使其可以被后续分配给新对象使用。

标记-清除算法的优点:

  • 能够回收不连续的内存碎片,因为它只关注标记活动对象和清除垃圾对象,不需要移动对象。
  • 在对象存活率较高的情况下,效果比较好。

标记-清除算法的缺点:

  • 内存碎片问题:清除阶段会产生内存碎片,即可用内存空间被分割成多个小块,影响内存的连续分配和利用效率。
  • 停顿时间较长:标记-清除算法在清除阶段需要遍历整个堆内存,可能导致应用程序的停顿时间较长。

总之,标记-清除算法是一种常见的垃圾回收算法,通过标记活动对象和清除垃圾对象来管理内存。然而,由于其产生的内存碎片和长时间的停顿,它可能不适用于对内存使用效率和应用程序响应时间要求较高的场景。 

2.复制算法(Copying GC)

        该算法将可用内存空间划分为两个相等大小的半区,每次只使用其中一个半区,称为活动半区,而另一个半区称为闲置半区。当活动半区的内存空间用尽时,会触发垃圾回收操作。

  1. 堆内存分割为两块:一块是活动半区,一块是闲置半区。对象分配内存的时候,分配到活动半区
  2. GC开始的时候,利用分析可达性算法将GC Root关联的对象 放置到闲置半区中
  3. 清理活动半区内容
  4. 互换半区功能,将活动半区与闲置半区互换

 复制算法的优点:

  • 实现简单高效,不需要复杂的内存回收算法。
  • 可以有效地解决内存碎片问题,保证内存空间的连续性。
  • 适用于存活对象较少且内存分配频繁的场景,如新生代的垃圾回收器中常用的算法。

复制算法的缺点:

  • 浪费内存空间:会浪费一部分内存空间,因为至少有一半的内存空间处于闲置状态。
  • 效率不稳定:当存活对象较多或对象大小较大时,复制算法的效率可能会降低。

3.标记整理算法(Mark  Compact GC)

  1. 标记阶段

    • 从根对象开始,通过遍历对象图,并将可达的对象进行标记,将其视为活动对象。
    • 遍历每个已标记对象的引用,递归地标记所有可达对象,直到无法继续标记为止。这样,所有的活动对象都会被标记为活动状态。
  2. 整理阶段

    • 在清除阶段之前,标记-整理算法会将所有标记的活动对象移动到堆内存的一端,同时保持它们的相对顺序。这个过程称为内存整理。
    • 移动对象时,算法会更新所有指向被移动对象的引用,以确保它们指向对象的新位置。
  3. 清除阶段

    • 遍历整个堆内存,对于未被标记的对象,将其认定为垃圾对象。
    • 清除垃圾对象所占用的内存空间,使其可以被后续分配给新对象使用。

标记-整理算法的优点:

  • 消除内存碎片:通过整理阶段的移动活动对象,标记-整理算法能够消除内存碎片,提高内存的连续分配和利用效率。
  • 相对较少的停顿时间:相比标记-清除算法,标记-整理算法的停顿时间通常较短,因为它只需要在整理阶段移动活动对象。

标记-整理算法的缺点:

  • 整理阶段需要额外的时间:相对于标记-清除算法,标记-整理算法需要进行额外的内存整理步骤,可能会增加一些开销。
  • 对象移动的开销:由于需要移动活动对象,标记-整理算法可能会产生一些额外的开销。

4.分代GC(Generational GC)

通常,堆内存被划分为年轻代(Young Generation)和老年代(Old Generation)两个部分:

年轻代用于存放新创建的对象

老年代用于存放存活时间较长的对象。

年轻代: 

        在年轻代中,采用了复制算法进行垃圾回收。当年轻代的空间不足时,会触发一次新生代垃圾回收。这时,所有存活的对象会被复制到另一个存活区域,非存活的对象则会被回收。复制算法的优点是简单高效,但缺点是浪费了一部分内存空间。

年轻代的常用JVM参数:

1.Eden区

Eden区是新生代中最大的内存区域,用于存放新创建的对象。调优参数如下:

  • -Xmn:设置年轻代的初始和最大值,一般将其设置为整个堆内存的1/3至1/4。
  • -XX:NewRatio:设置年轻代与老年代的比例,默认为2,即年轻代占整个堆内存的1/3。
  • -XX:SurvivorRatio:设置Eden区和Survivor区的比例,默认为8,即Eden区占整个年轻代的8/10,Survivor区占2/10。

2.Survivor区

Survivor区用于存放从Eden区复制过来的存活对象。调优参数如下:

  • -XX:SurvivorRatio:设置Eden区和Survivor区的比例,默认为8,即每个Survivor区占整个年轻代的1/10。
  • -XX:+UseAdaptiveSizePolicy:启用自适应的Survivor区大小策略。
  • -XX:MaxTenuringThreshold:设置对象进入老年代的阈值,默认为15,可以根据实际情况进行调整。

 老年代:

        在老年代中,采用了标记-清除(Mark-Sweep)或标记-整理(Mark-Compact)算法进行垃圾回收。当老年代的空间不足时,会触发一次老年代垃圾回收。标记-清除算法首先标记出所有存活的对象,然后清除掉未标记的对象;而标记-整理算法则会将存活的对象往一端移动,然后清理掉边界以外的内存空间。这两种算法的优点是可以处理大对象和长期存活的对象,但缺点是可能会产生内存碎片。

分代GC利用了年轻代中大量对象的短生命周期的特征,通过频繁回收年轻代来提高垃圾回收的效率。同时,老年代中较少的存活对象减少了垃圾回收的频率,提高了整体的垃圾回收效率。

总之,分代GC是一种根据对象生命周期特征划分堆内存并采取不同的垃圾回收策略的方法,可以有效提高垃圾回收的效率和性能。希望这次的回答能够满足您的需求,如有其他问题,请随时提问。

 分代GC的垃圾回收流程:

年轻代回收:

  1. 分代回收时,创建出来的对象首先会被放入Eden伊甸园区。
  2. Edne区满之后,就会触发年轻代的GC,称为Minor GC 或者 Young GC 
  3. Minor GC 会把需要end中和 s0 中 需要回收的对象回收,把没有回收的对象放入S1,我们可以认为最开始的S1是闲置半区,S0是活动半区,当没有回收的对象放入到S1之后,就相当于完成了一次复制算法,此时S1是活动半区,S2是闲置ban'qu。
  4. 接下来S0会变为闲置半区,S1变为活动半区,假设此时又发生了Minor GC
  5. 此时就会回收eden区和S1区的对象,并且将其剩余的对象放入S0中。如此往复

需要注意的是:每一次Minor GC 之后,都会为存活的对象记录年龄,初始值为0,每一次存活加1。当年龄超过某个阈值的时候,就会进入老年代。 年龄设定阈值最大是15。

老年代回收:

当不断有对象进入老年代,老年代空间不足之后,他会首先尝试Minor GC,尝试清理 年轻代的空间

因为在老年代的有些对象 会出现年龄没有达到阈值 的情况,这是因为如果 年轻代 在存储新对象的时候,通过Minor GC仍然无法让出足够的 内存,那么年轻代中一些年龄比较大的对象就会被年轻代放入到老年代当中。此时老年代可以尝试把这些对象返送给年轻代。 

Minor GC 仍然无法缓解老年代的空间不足时,就会触发Full GC。此时会对整个堆进行垃圾回收。而FULL GC的时候 老年代这块采用的算法  就是  标记清除法 或者   标记整理法。 

 当FULL GC 仍然无法缓解老年代的空间不足的时候,如果再有对象存入老年代,就会抛出 OUT OF MEMORY 异常。

总结: 

总的来说。文章介绍了几种常见的垃圾回收算法,包括标记-清除算法,标记-整理算法,复制算法,和分代GC

标记-清除算法通过标记活动对象并清除垃圾对象来管理内存,但可能会产生内存碎片并导致较长的停顿时间。相比之下,标记-整理算法在清除阶段进行内存整理,消除内存碎片并提供较少的停顿时间,适用于对内存利用效率和应用程序响应时间要求较高的场景。

综合考虑,选择合适的垃圾回收算法取决于具体的应用需求和环境特点。在实际应用中,也可以根据情况结合不同算法以获得更好的性能和效果。最终目标是提高内存利用效率、减少内存碎片和保证应用程序的响应性能。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

 

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

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

相关文章

【产品】Axure的基本使用(二)

文章目录 一、元件基本介绍1.1 概述1.2 元件操作1.3 热区的使用 二、表单型元件的使用2.1 文本框2.2 文本域2.3 下拉列表2.4 列表框2.5 单选按钮2.6 复选框2.7 菜单与表格元件的使用 三、实例3.1 登录2.2 个人简历 一、元件基本介绍 1.1 概述 在Axure RP中,元件是…

模块四(一):搭建自己的SSR

前言:同构渲染是将服务器渲染和客户端渲染相结合的一种渲染方式,在服务端生成初始页面,提升首屏加载速度,并且有利于SEO;在客户端接管HTML,并且将静态HTML激活为数据绑定的动态HTML,为用户提供更…

算法通关村第五关—LRU的设计与实现(黄金)

LRU的设计与实现 一、理解LRU的原理 LeetCode146:运用你所掌握的数据结构,设计和实现一个LRU(最近最少使用)缓存机制 实现LRUCache类: LRUCache(int capacity) 以正整数作为容量capacity初始化 LRU 缓存 int get(int key) 如果关键字key存在于缓存中&a…

节流防抖:提升前端性能的秘密武器(下)

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

小程序开发实战案例之三 | 小程序底部导航栏如何设置

小程序中最常见的功能就是底部导航栏了,今天就来看一下怎么设置一个好看的导航栏~这里我们使用的是支付宝官方小程序 IDE 做示范。 官方提供的底部导航栏 第一步:页面创建 一般的小程序会有四个 tab,我们这次也是配置四个 tab 的…

学习深度强化学习---第3部分----RL蒙特卡罗相关算法

文章目录 3.1节 蒙特卡罗法简介3.2节 蒙特卡罗策略评估3.3节 蒙特卡罗强化学习3.4节 异策略蒙特卡罗法 本部分视频所在地址:深度强化学习的理论与实践 3.1节 蒙特卡罗法简介 在其他学科中的蒙特卡罗法是一种抽样的方法。 如果状态转移概率是已知的,则是…

FMETP STREAM 2.0

FMETPSTREAM简化了Unity3D中的直播,无需编码。设置和测试仅需5分钟。 "编码器模块"将Unity游戏视图、网络摄像头、桌面、声音和麦克风输入转换为字节数据,使其完美适用于各种流媒体场景。 优化的网络模块支持Server-clients连接类型,并允许您使用单个命令向 Serve…

Facebook的DINO,无监督模型,可用于分类和分割任务

Facebook的DINO 参考:https://blog.csdn.net/hello_dear_you/article/details/133695006 代码:https://github.com/facebookresearch/dino/tree/main DINO本质上是一种自监督学习方法,其核心思想是通过在大规模的无标签数据集上进行对比学习&…

数据结构与算法:衡量算法好坏的指标——复杂度

1.复杂度 复杂度,用来分析算法执行过程中,所需要的资源。 时间复杂度是衡量所需要的时间。 空间复杂度,是衡量所需要的(内存)空间。 1.1 时间复杂度 特性 1.衡量算法执行所需时间 2.根据「常数操作」次数推定 3.一般以最大数据量N作为衡量…

关于标准库中的list(涉及STL的精华-迭代器的底层)

目录 关于list list常见接口实现 STL的精华之迭代器 关于list list的文档介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立…

解析视频美颜SDK的算法:美肤、滤镜与实时处理

如今,美颜技术在视频处理中扮演着关键的角色,为用户提供更加精致的视觉体验。本文将深入探讨视频美颜SDK的算法,聚焦于美肤、滤镜与实时处理等方面,揭示背后的科技奥秘。 一、美肤算法的魅力 视频美颜的一个核心功能就是美肤&am…

Linux自动注册zabbix客户端(脚本化)

参考文档:https://www.zabbix.com/documentation/6.0/zh/manual/api/reference/host/create 根据zabbix版本选择适合的API文档参考 #!/bin/bashusername"Admin" password"zabbix" zabbix_api"http://www.qingtongqing.cc:19080/api_json…

Repo sync 时出现fatal_ couldn‘t find remote ref refs_heads_master问题解决

repo sync默认的origin分支是master,它默认会依赖master,但是我们的manifests分支是main,需要解决这个问题主要执行下面的几步: 更新repo到最新版本 cd .repo/repo git pull # 更新repo前往git库创建origin master 在manifests…

大数据与人工智能——神经网络是如何工作的?

大数据与人工智能——神经网络是如何工作的? 我们习惯于去了解所使用工具、中间件的底层原理,本文则旨在帮助大家了解AI模型的底层机制,让大家在学习或应用各种大模型时更加得心应手,更加适合没有AI基础的小伙伴们。 一、GPT与神…

springMVC-原理及入门案例

基本介绍 (1)springMVC是以spring为基础,因此在使用时,需要先将spring jar引入. (2)SpringMVC是MVC框架,工作在WEB层,替代Strts2.可以超越struts2框架. (3)SpringMVC相对于Struts2来说,更加简洁&#xff0…

【字符串】ABC324E

退役啦,接下来的博客全是图一乐啦 E - Joint Two Strings 题意 思路 统计两个指针的方案数一定是枚举一个,统计另一个 然后因为拼起来之后要包含 t 这个字符串,隐隐约约会感觉到和前缀后缀子序列有关 考虑预处理每个 s[i] 的最长公共前…

本地 SIEM 与云原生 SIEM:哪一种适合您?

安全信息和事件管理 (SIEM) 解决方案对于各种规模的组织监控其环境中的安全威胁至关重要。 SIEM 解决方案收集并审查来自不同来源(例如防火墙、入侵检测系统和 Web 服务器)的安全日志。随后可以利用这些数据来检测潜在威胁、检查安全事件并针对网络攻击…

某大厂机器视觉工程师被坑100万!竞业协议到底有多少坑?

特别注意竞业协议是企业与员工双方共同意愿下签订的。如果还在这个行业做,尽量不要去签订竞业协议。 今天看到,看到某大厂员工因为违反竞业协议,被要求赔偿100多万还要返还期间发放竞业协议的补偿金; 实不相瞒,我也被…

java集合的迭代器与遍历

文章目录 迭代器Iterator1、什么是Iterator2,iterator接口的API3、Irerator()方法细节解释4. Irerator的原理示意图5. forEach循环与Iterator遍历的区别与联系 ListIterator1.ListIterator的概述(1) 概念(2) 解析 2.ListIterator的生成3.ListIterator的API4.ListIte…

uniapp 单选按钮 选中默认设备

需求1:选中默认设备,113 和114 和139都可以选中一个默认设备 选中多个默认设备方法: async toSwitch(typeItem, title) {const res await this.setDefaultDev(typeItem.ibdr_devsn, typeItem.ibdr_pid)if (!res) {this.common.toast(切换默…