十分钟让你搞懂JVM中的GC垃圾回收机制(分代回收)

文章目录

  • 0. 为什么要有垃圾回收?
  • 1. 垃圾回收哪个内存区域?
  • 2. 如何找到垃圾(死亡对象的判断)
    • 2.1 引用计数法
    • 2.2 可达性分析法
    • 2.3 两种算法的差别
  • 3. 如何清理垃圾(死亡对象的回收)
    • 3.1 标记-清楚法
    • 3.2 复制法
    • 3.3 标记-整理法
  • 4. JVM使用的回收方法
    • 4.1 什么是分代回收
    • 4.2 哪些对象会进入新生代?哪些对象会进入老年代?
    • 4.3 工作过程
  • 5. 垃圾回收器是什么
  • 总结


0. 为什么要有垃圾回收?

JVM 中的垃圾回收机制, 可以自动的释放不再使用的内存. 可以有效的防止程序中内存泄漏问题. 本文我们就来聊一下垃圾回收机制.

内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

关注收藏, 开始学习吧🧐


1. 垃圾回收哪个内存区域?

Java运行时内存的有许多区域。对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言,其生命周期与相关线程有关,随线程而生,随线程而灭。并且这三个区域的内存分配与回收具有确定性,因为当方法结束或者线程结束时,内存就自然跟着线程回收了。

因此本文所讲的有关内存分配和回收关注的为Java 堆 与 方法区 这两个区域。

垃圾回收, 应该分为两步:

  1. 找到垃圾.
  2. 清理垃圾.

对于 Java 来说, 垃圾回收, 回收的是 “对象”, 而不是 “字节”. 所以我们会认为 “垃圾” 指的就是 “已经死亡的对象”, 那么我们如何判定这个对象是否已经死亡, 是否是垃圾呢?

2. 如何找到垃圾(死亡对象的判断)

如果一个对象, 在后续的代码中, 不会被继续使用到了, 就可以视为是垃圾了. 那么我们该怎样判断这个对象不会再被继续使用到了呢?

在 Java 中, 使用一个对象, 只有一种途径, 就是搞个引用指向它, 然后通过引用来访问这个对象.

  • 一个对象, 只要有引用指向, 就无法确保后续孩会不会进行使用.
  • 一个对象, 如果没有引用指向, 那么这个对象以后一定无法被使用.

所以我们可以认为, 一个对象, 如果没有任何引用指向它, 就代表着之后也不会被使用到了, 那它就是一个 “垃圾” 了. 接下来我们来介绍两个主流的判断方法.

2.1 引用计数法

该方法简单来说, 就是给每个对象中安排一个计数器, 每次有引用指向它时, 内置的计数器就 +1. 每次有引用被销毁时, 计数器就 -1. 当计数器成为 0 时, 意味着该对象就变成垃圾了.

引用计数法实现简单, 判定效率也比较高, 在大部分情况下都是一个不错的算法, 比如 Python 语言就采用引用计数法进行内存管理.

但上述方案, 并不是 JVM 中判断垃圾所使用的方案. 是因为引用技术方案, 还存在着两个无法忽视的问题:

  1. 空间利用率会比较低, 浪费了不必要的内存空间. 如果一个对象本体只有 4 个字节时, 给引用计数分配 2 个字节, 就相当于浪费了 50% 的内存空间.
  2. 可能会存在循环引用的问题, 导致对象不能被正常识别为垃圾.

观察循环引用问题.
在这里插入图片描述
当前是简单画了一个内存草图, 我们执行左面的伪代码, 就会造成右面的内存布局. 可以看到, 明明已经没有引用指向对象了, 可是对象中的计数器, 还没有到 0. 此时这俩对象的引用计数不为 0, 就不能被视为垃圾, 也就无法被识别清理.

2.2 可达性分析法

上面我们说到, Java并不是采用引用计数法来判断对象是否已经"死亡", 其采用的其实是 “可达性分析法”.

JVM 首先会从现有代码中能直接访问到的引用出发, 尝试遍历所有能访问的对象. 只要这个对象能被访问到, 就被视为 “可达”, 反之为不可达. 完成整个遍历后, 视所有 “不可达” 的对象为垃圾.

此算法的核心思想为 : 通过一系列称为 “GC Roots” 的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称之为"引用链",当一个对象到 GC Roots 没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的。以下图为例:

在这里插入图片描述
对象 Object5-Object7 之间虽然彼此还有关联,但是它们到GC Roots是不可达的,因此他们会被判定为可回收对象。

在 Java 中,可作为GC Roots的对象包含下面几种:

  1. 栈上的局部变量.
  2. 方法区中类静态属性引用的对象;
  3. 方法区中常量引用的对象。

2.3 两种算法的差别

  • 引用计数消耗的是空间, 通过引用计数的数值, 不需要持续判断, 就可以非常快速的得知这个对象是否是垃圾.
  • 可达性分析消耗的是时间, 不消耗额外的空间开销, 通过持续性的扫描, 就可以得知哪些对象是垃圾.

3. 如何清理垃圾(死亡对象的回收)

我们找到垃圾之后, 就应该对它进行清理了. 目前主流的一些清理方法有以下几种.

3.1 标记-清楚法

"标记-清除"算法是最基础的收集算法。算法分为"标记"和"清除"两个阶段 : 首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。但该算法也有一些问题.

"标记-清除"算法的不足主要有两个 :

  1. 效率问题 : 标记和清除这两个过程的效率都不高
  2. 空间问题 : 标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集。

在申请内存时, 都是申请的连续内存空间, 释放内存, 就可能会破坏原有的连续性, 导致 “有内存, 但无法申请”.

在这里插入图片描述
假设当前剩余四块空间(黑色的)可以申请, 每个空间大小是 1mb, 总的空闲空间是 4mb, 但其实实际上已经无法继续分配大于 1mb 的内存了. 这种问题就叫做 “内存碎片” 问题.

3.2 复制法

"复制"算法是为了解决"标记-清理"的问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。

在这里插入图片描述

就是把一个内存, 分成两份空间 A 和 B, 只用一份A. 清理时, 把 A 中存活下来的对象全部复制到 B 中, 把 A 中内存统一释放 接下来就继续使用 B 空间. 再次清理时, 把存活下来的对象再复制回 A 中去, 把 B 中资源统一释放. 当前流程一直循环进行.

这个算法虽然提高了一些效率, 但也有些不足的地方,

  • 内存李永利比较低, 他真正能利用的内存空间, 只有原先内存空间的一半, 很浪费内存空间.
  • 在对象存活率较高时会进行比较多的复制操作, 效率会变低.

3.3 标记-整理法

针对 “标记-清楚” 提出了一种为"标记-整理"的算法。标记过程仍与 “标记-清除” 过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动,然后直接清理掉端边界以外的内存。

在这里插入图片描述

这样的方式, 避免了刚才复制算法中内存利用率比较低的问题. 但是也有个很明显的个问题, 就是这里搬运的成本, 也是比较高的.

4. JVM使用的回收方法

设计 JVM 中垃圾回收算法时, 虽然已经有了这么多的回收机制, 但还是没有哪个方法能让设计 JVM 的大佬们满意, 于是他们想了个办法, 集百家之长, 结合上面的回收方案, 搞一个综合性质的方案, 在不同的场景下, 使用不同的回收方式, 做到扬长而避短.

4.1 什么是分代回收

分代算法和上面讲的 3 种算法不同,分代算法是通过区域划分,实现不同区域和不同的垃圾回收策略,从而实现更好的垃圾回收。对于不同的情况设置更符合该情况的规则,从而达到更高的效率,这就是分代算法的设计思想。

当前 JVM 垃圾收集都采用的是"分代收集(Generational Collection)"算法,这个算法并没有新思想,只是根据对象存活周期的不同将内存划分为几块。一般是把 Java 堆分为新生代和老年代。在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用复制算法;而老年代中对象存活率高、没有额外空间对它进行分配担保,就必须采用"标记-清理"或者"标记-整理"算法。

4.2 哪些对象会进入新生代?哪些对象会进入老年代?

  • 新生代:一般创建的对象都会进入新生代;
  • 老年代:大对象和经历了 N 次(一般情况默认是 15 次)垃圾回收依然存活下来的对象会从新生代移动到老年代。

4.3 工作过程

在这里插入图片描述

  • 堆内存为两个区:新生代 (Young) 和老年代 (Old);
  • 新生代默认占堆内存的 1/3,老年代默认占堆内存的 2/3;
  • 新生代又分为 Eden 区、Survivor From区、Survivor To区默认比例是 8:1:1.

先理解两种GC:

  1. Minor GC 又称为 新生代GC : 指的是发生在新生代的垃圾收集。因为Java对象大多都具备朝生夕灭的特性,因此Minor GC(采用复制算法)非常频繁,一般回收速度也比较快。
  2. Full GC 又称为 老年代GC 或者 Major GC : 指发生在老年代的垃圾收集。出现了 Major GC,经常会伴随至少一次的 Minor GC。Major GC 的速度一般会比 Minor GC 慢10倍以上。

工作过程

  • 所有新创建的对象都在 Eden 区,当 Eden 区内存满后将 Eden 区+ Survivor From 区存活的对象复制到 Survivor To区;
  • 清空 Eden 区与 Survivor From 区;
  • 同时 Survivor From 与 Survivor To 分区进行交换;
  • 每次 Minor GC 存活对象年龄加 1,当年龄达到 15(默认值)岁时,被移到老年代;
  • 当 Eden 的空间无法容纳新创建的对象时,这些对象直接被移至老年代;
  • 当老年代空间占用达到阈值时,触发 Full GC;
  • 以上流程循环执行。

在这里插入图片描述

5. 垃圾回收器是什么

如果说上面我们讲的收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。

垃圾收集器的作用:垃圾收集器是为了保证程序能够正常、持久运行的一种技术,它是将程序中不用的死亡对象也就是垃圾对象进行清除,从而保证了新对象能够正常申请到内存空间。

以下这些收集器是不同版本推出的重要的垃圾收集器, 读者了解一下即可.
在这里插入图片描述


总结

✨ 本文重点讲解了垃圾回收的一些概念, 包括怎么找垃圾, 怎么清理垃圾等等.
✨ 想了解更多知识, 请持续关注博主, 本人会不断更新学习记录, 跟随我一起不断学习.
✨ 感谢你们的耐心阅读, 博主本人也是一名学生, 也还有需要很多学习的东西. 写这篇文章是以本人所学内容为基础, 日后也会不断更新自己的学习记录, 我们一起努力进步, 变得优秀, 小小菜鸟, 也能有大大梦想, 关注我, 一起学习.

再次感谢你们的阅读, 你们的鼓励是我创作的最大动力!!!!!

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

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

相关文章

【Linux】:信号的产生

信号 一.前台进程和后台进程1.前台进程2。后台进程3.总结 二.自定义信号动作接口三.信号的产生1.键盘组合键2.kill信号进程pid3.系统调用1.kill函数2.raise函数3.abort函数 四.异常五.软件条件六.通过终端按键产生信号 一.前台进程和后台进程 1.前台进程 一个简单的代码演示 …

跟着chatgpt学习|1.spark入门

首先先让chatgpt帮我规划学习路径,使用Markdown格式返回,并转成思维导图的形式 目录 目录 1. 了解spark 1.1 Spark的概念 1.2 Spark的架构 1.3 Spark的基本功能 2.spark中的数据抽象和操作方式 2.1.RDD(弹性分布式数据集) 2…

JAVA时间常用操作工具类

小刘整理了JAVA中对时间的常用操作,封装了几种方法,简单方便,开箱即用。时间转字符串格式,字符串转时间,以及过去和未来的日期。除此之外,还新增了时间戳之差计算时分秒天的具体方案。 public static void …

【力扣:1707 1803】0-1字典树

思路:树上每个节点存储拥有该节点的数组元素的最小值,left节点表示0,right节点表示1,构建完成后遍历树当子节点没有比mi小的元素时直接输出-1,否则向下构造。 struct tree{int m;tree*leftnullptr,*rightnullptr;tree…

智能优化算法应用:基于海鸥算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于海鸥算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于海鸥算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.海鸥算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

养生馆服务预约会员管理系统小程序效果如何

中医养生馆的全国数量逐渐增加,各种疾病困扰下,有些病往往通过养生馆即可治好,比如常见的针灸、按摩、药理滋补、切脉等,都有很高的市场需求度,而随着众多商家入局赛道及消费升级,传统中医养生馆经营痛点也…

深度学习第3天:CNN卷积神经网络

☁️主页 Nowl 🔥专栏《机器学习实战》 《机器学习》 📑君子坐而论道,少年起而行之 ​ 文章目录 介绍 CNN的主要结构 卷积层 激励层 池化层 Kears搭建CNN 搭建代码 直观感受卷积的作用 结语 介绍 卷积神经网络(Convol…

印刷基板开孔机上的直线导轨怎么安装?

直线导轨是属于高精度的传动元件,作为印刷基板开孔机重要的传动元件,倘若安装不当,严重则无法正常作业,轻则影响直线导轨的精度和寿命。那么,印刷基板开孔机的直线导轨是如何安装的呢? 在安装前&#xff0c…

C语言编译过程再解析

多年以前,分析过编译过程,并写了一篇博客,现在对编译过程有了更广阔的认识,记录在此 编译过程 中的 链接与 编译 编译过程分为1. 预处理2. 编译3. 汇编4. 链接其中有 2个过程比较特殊,1. 编译2. 链接对于C程序来说,链接分为提前链接(静态链接)对应下图第1行运行时链接(动态链…

Spring Boot 改版如何解决?使用阿里云创建项目、使用IDEA进行创建

接上次博客:JavaEE进阶(2)SpringBoot 快速上手(环境准备、Maven:核心功能,Maven仓库、第⼀个SpringBoot程序:Spring介绍,Spring Boot介绍、创建项目)-CSDN博客 目录 使…

深度学习技巧应用30-深度学习中的GPU的基本架构原理与应用技巧

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用30-深度学习中的GPU的基本架构原理与应用技巧,GPU是一种专门用于处理大量并行操作的硬件设备,它的架构设计主要是为了图形渲染。然而,由于其并行处理能力,现在广泛应用于深度学习、科学计算等领域。主要的GPU制造商…

智能优化算法应用:基于蝗虫算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于蝗虫算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于蝗虫算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝗虫算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

高并发内存池

1.什么是内存池 内存池动态内存分配与管理技术,对于程序员来说,通常情况下,动态申请内存需要使用new,delete,malloc,free这些API来申请,这样导致的后果是,当程序长时间运行之后,由于程序运行时所申请的内存…

C#文件基本操作(判断文件是否存在、创建文件、复制或移动文件、删除文件以及获取文件基本信息)

目录 一、判断文件是否存在 1.File类的Exists()方法 2.FileInfo类的Exists属性 二、创建文件 1.File类的Create()方法 2.FileInfo类的Create()方法 三、复制或移动文件 1.File类的Copy()方法 2.File类的Move()方法 3.FileInfo类的CopyTo()方法 四、删除文件 1.File…

install pnpm : 无法加载文件的解决办法

问题描述 我在使用pnpm的时候报错 PS D:\emss\pure-admin-backend> pnpm install pnpm : 无法加载文件 C:\Users\RD-16\AppData\Roaming\npm\pnpm.ps1。未对文件 C:\Users\RD-16\AppData\Roaming\npm\pnpm.ps1 进行数字签名。无法在当前系统上运 行该脚本。有关运行脚本和设…

YOLOv5改进 | 添加SE注意力机制 + 更换NMS之EIoU-NMS

前言:Hello大家好,我是小哥谈。为提高算法模型在不同环境下的目标识别准确率,提出一种基于改进 YOLOv5 深度学习的识别方法(SE-NMS-YOLOv5),该方法融合SE(Squeeze-and-Excitation)注…

13年老鸟总结,性能测试方法汇总+性能响应很慢排查方法(详全)

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 1、性能测试包含哪…

CSS水平居中与垂直居中的方法

当我们页面布局的时候&#xff0c;通常需要把某一个元素居中&#xff0c;这一篇文章为大家介绍一下居中的几种方法&#xff0c;本人文笔有限&#xff0c;请见谅&#xff01; 一.水平居中 行内元素水平居中的方法&#xff0c;我们使用text-align:center; <!DOCTYPE html&g…

[计算机网络]运输层概述

虽然我自己也不知道写在前面和前言有什么区别..... 这个系列其实是针对<深入浅出计算机网络>的简单总结,加入了一点个人的理解和浅薄见识,如果您有一些更好的意见和见解,欢迎随时协助我改正,感激不尽啦. 最近心态平和了不少, 和过去也完全做了个割舍吧,既然痛苦和压力的…

透过对话聊天聊网络tcp三次握手四次挥手

序 说起来网络&#xff0c;就让我想起的就是一张图。我在网上可以为所欲为&#xff0c;反正你又不能顺着网线来打我。接下来我们来详细说一下网络到底是怎么连接的。 TCP三次打招呼 首先我会用男女生之间的聊天方式&#xff0c;来举一个例子。 从tcp三次握手来说&#xff0c;…