首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【愚公系列】2023年11月 大数据教学课程 011-JVM垃圾回收算法

【愚公系列】2023年11月 大数据教学课程 011-JVM垃圾回收算法

作者头像
愚公搬代码
发布2025-06-02 15:37:29
发布2025-06-02 15:37:29
9400
代码可运行
举报
文章被收录于专栏:历史专栏历史专栏
运行总次数:0
代码可运行

🚀一、垃圾回收

🔎1.垃圾回收相关概念

🦋1.1 C/C++语言的垃圾回收

C/C++语言是非常底层的语言,没有内置的垃圾回收机制,是通过new关键字申请内存资源,通过delete关键字释放内存资源。。这意味着程序员需要手动分配和释放内存,并负责管理程序的堆栈内存和堆内存。

为了确保堆内存的正确释放,程序员必须跟踪所有分配的内存,并在使用完毕后手动释放它们。这是非常困难和容易出错的,因为程序员需要考虑到对象的生命周期和所有可能的退出路径。

如果,程序员在某些位置没有写delete进行释放,那么申请的对象将一直占用内存资源,最终可能会导致内存溢出。

🦋1.2 Java语言的垃圾回收

Java语言的垃圾回收是指Java虚拟机自动管理内存分配和释放的机制。Java虚拟机会周期性地扫描内存中的对象,找到不再被引用的对象并回收它们的内存,避免了手工释放内存的复杂性和风险。

Java垃圾回收的实现采用的是可达性算法。当一个对象没有任何引用指向它时,即成为无用对象。Java虚拟机会通过一连串的引用关系,判断一个对象是否还能被其他对象访问,如果不能,就会将其回收。

Java垃圾回收的优点是可以让程序员专注于业务逻辑,而不需要关心内存的分配与释放。缺点是可能会影响程序的性能,因为垃圾回收需要消耗一定的计算资源。同时,由于Java虚拟机并不知道如何处理本地资源,因此需要手动释放本地资源,避免发生内存泄漏。

🔎2.垃圾回收的常见算法

常见的垃圾回收算法有:引用计数法、标记清除法、标记压缩法、复制算法、分代算法等。

🦋2.1 引用计数法
☀️2.1.1 原理

引用计数法是一种垃圾回收算法,其核心思想是给每个对象添加一个计数器,用于记录当前有多少个引用指向该对象,当引用计数为0时,可以将该对象视为垃圾进行回收。

引用计数法是最早的垃圾回收算法之一,它的实现非常简单,每个对象都有一个引用计数器,当对象被引用时计数器加一,当引用被取消时计数器减一,当计数器为0时,该对象就可以被回收了。引用计数法的优点是实现简单,回收及时,但是它存在循环引用的问题。

循环引用是指两个或多个对象互相引用形成一个闭环的情况,这种情况下,引用计数器的引用计数永远不会为0,导致这些对象无法被垃圾回收器回收,造成内存泄漏的问题。

☀️2.1.2 优缺点

优点:

  • 实时性较高,无需等到内存不够的时候,才开始回收,运行时根据对象的计数器是否为0,就可以直接回收。
  • 在垃圾回收过程中,应用无需挂起。如果申请内存时,内存不足,则立刻报outofmember 错误。
  • 区域性,更新对象的计数器时,只是影响到该对象,不会扫描全部对象。

缺点:

  • 每次对象被引用时,都需要去更新计数器,有一点时间开销。
  • 浪费CPU资源,即使内存够用,仍然在运行时进行计数器的统计。
  • 无法解决循环引用问题。(最大的缺点)

案例:

代码语言:javascript
代码运行次数:0
运行
复制
class TestA{
  public TestB b;
 
}
class TestB{
  public TestA a;
}
public class Main{
    public static void main(String[] args){
        A a = new A();
        B b = new B();
        a.b=b;
        b.a=a;
        a = null;
        b = null;
   }
}

虽然a和b都为null,但是由于a和b存在循环引用,这样a和b永远都不会被回收。

🦋2.2 标记清除法
☀️2.2.1 原理

标记清除法是一种垃圾回收算法,其基本原理是在程序执行时标记所有可以访问的对象,然后清除所有没有被标记的对象,将空间进行回收。

该算法的具体步骤如下:

  1. 从根节点开始遍历所有可以访问的对象,并标记它们;
  2. 遍历整个堆,将没有被标记的对象清除;
  3. 对空闲内存进行合并,形成一块大的空闲内存。

该算法的优点是能够回收所有可以访问的未使用的内存空间,而不会回收正在使用的内存空间。缺点是在执行过程中会暂停程序,因为需要在执行过程中遍历所有可访问的对象。此外,该算法可能会导致内存碎片的问题,因为清除的对象可能不是连续的内存空间。

流程图解:

没有被标记的对象将会回收清除掉,而被标记的对象将会留下,并且会将标记位重新归0。接下来就不用说了,唤醒停止的程序线程,让程序继续运行即可。

☀️2.2.2 优缺点

可以看到,标记清除算法解决了引用计数算法中的循环引用的问题,没有从root节点引用的对象都会被回收。

同样,标记清除算法也是有缺点的:

  • 效率较低,标记和清除两个动作都需要遍历所有的对象,并且在GC时,需要停止应用程序,对于交互性要求比较高的应用而言这个体验是非常差的。
  • 通过标记清除算法清理出来的内存,碎片化较为严重,因为被回收的对象可能存在于内存的各个角落,所以清理出来的内存是不连贯的。
🦋2.3 标记压缩算法
☀️2.3.1 原理

垃圾回收的标记压缩算法是一种内存回收机制,它主要是为了解决动态内存分配造成的内存碎片问题,以及避免内存泄漏等问题。下面介绍其主要原理:

  1. 标记阶段:首先标记所有被引用的对象和内存块,标记的方法有两种,分别是根搜索和追溯搜索。根搜索从系统根开始遍历,找到所有被引用的对象,追溯搜索则是从被引用的对象开始遍历,找到所有被引用的对象。标记完后,会将所有被引用的对象打上标记,也就是将其标记为“活动对象”。
  2. 压缩阶段:将所有活动对象向一端移动,并且将空闲的内存块合并,从而避免内存碎片。这里需要记录活动对象的新地址,并将所有指针的值修改为新地址。
  3. 清除阶段:删除未被标记的对象(即未被引用的对象),回收它们所占用的内存。这个过程就是垃圾回收的核心,也是内存回收的最终目标。
☀️2.3.2 优缺点

优缺点同标记清除算法,解决了标记清除算法的碎片化的问题,同时,标记压缩算法多了一步,对象移动内存位置的步骤,其效率也有有一定的影响。

🦋2.4 复制算法
☀️2.4.1 原理

复制算法是一种基于空间换时间的垃圾回收算法。其主要思想是将堆空间分为两个部分:From空间和To空间。在程序运行过程中,所有的新生代对象都被分配在From空间中,当From空间被占用到一定程度时,就会触发垃圾回收机制。

回收的过程如下:

  1. 垃圾回收器会从根对象出发,扫描From空间中所有可达对象;
  2. 扫描过程中,将所有可达对象复制到To空间中,并在From空间中标记已复制的对象;
  3. 扫描结束后,将From空间和To空间互换,此时原来的To空间成为新的From空间,原来的From空间成为新的To空间;
  4. 清空原来的From空间。

通过复制算法,可以有效避免内存碎片的产生,提高垃圾回收效率。但是它需要两倍的堆空间,并且需要对整个堆空间进行复制操作,因此对于大型对象或存活率较高的情况,复制算法的效率会下降,不适合用来回收老年代对象。

☀️2.4.2 优缺点

优点:

  • 在垃圾对象多的情况下,效率较高
  • 清理后,内存无碎片

缺点:

  • 在垃圾对象少的情况下,不适用,如:老年代内存
  • 分配的2块内存空间,在同一个时刻,只能使用一半,内存使用率较低
🦋2.4 分代算法

分代算法是目前主流的垃圾回收算法之一。

分代算法的基本思想是将内存中的对象按照其存活时间分为不同的“代”,然后在垃圾回收时优先考虑清理那些存活时间短的对象,从而减少垃圾回收的时间和工作量。

一般来说,分代算法将内存分为三代:年轻代、中年代和老年代。年轻代是指所有新创建的对象的集合,这些对象通常有较短的生命周期,很快就会被垃圾回收。中年代是指存活时间较长的对象,通常是在年轻代经历了多次垃圾回收后仍然存活的对象,这些对象不太容易被回收。而老年代则是指存活时间最长的对象,这些对象通常是一些单例对象或缓存对象,它们的存活时间非常长,很少被回收。

分代算法中的年轻代通常采用“复制”算法进行垃圾回收。具体来说,年轻代被分为两个等大小的空间,称为“from”空间和“to”空间。在垃圾回收时,所有存活的对象都会被复制到to空间中,而from空间则被清空。年轻代空间的大小一般比较小,所以它的垃圾回收比较频繁,但是回收的效率也比较高。

中年代和老年代通常采用“标记-清除”或“标记-整理”算法进行垃圾回收。在标记-清除算法中,首先标记所有存活的对象,然后清除所有未标记的对象。在标记-整理算法中,标记所有存活的对象,然后将这些对象紧凑排列,清理掉其他的空间。

分代算法其实就是这样的,根据回收对象的特点进行选择,在jvm中,年轻代适合使用复制算法,老年代适合使用标记清除或标记压缩算法。


🚀感谢:给读者的一封信

亲爱的读者,

我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。

如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。

我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-11-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🚀一、垃圾回收
    • 🔎1.垃圾回收相关概念
      • 🦋1.1 C/C++语言的垃圾回收
      • 🦋1.2 Java语言的垃圾回收
    • 🔎2.垃圾回收的常见算法
      • 🦋2.1 引用计数法
      • 🦋2.2 标记清除法
      • 🦋2.3 标记压缩算法
      • 🦋2.4 复制算法
      • 🦋2.4 分代算法
  • 🚀感谢:给读者的一封信
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档