• 【JVM】垃圾收集算法


    分代收集理论

    当前商业虚拟机的垃圾收集器,大多数都遵循了“分代收集”(Generational Collection)[1]的理论进 行设计,分代收集名为理论,实质是一套符合大多数程序运行实际情况的经验法则,它建立在两个分代假说之上:

    1. 弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的。

    2. 强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消 亡。

    把分代收集理论具体放到现在的商用Java虚拟机里,设计者一般至少会把Java堆划分为新生代 (Young Generation)和老年代(Old Generation)两个区域[2]。顾名思义,在新生代中,每次垃圾收集 时都发现有大批对象死去,而每次回收后存活的少量对象,将会逐步晋升到老年代中存放。

    对于分代理论,由于会存在老年代引用新生代的情况,这对于回收对象时的判断会造成性能影响,所以还应该有下面假说

    1. 跨代引用假说(Intergenerational Reference Hypothesis):跨代引用相对于同代引用来说仅占极少数。

    上面条结论可根据前两条假说逻辑推理得出的隐含推论:存在互相引用关系的两个对象,是应该倾向于同时生存或者同时消亡的。

    下面是一些常见的分代收集名词

    • 部分收集(Partial GC):指目标不是完整收集整个Java堆的垃圾收集,其中又分为:

      • 新生代收集(Minor GC/Young GC):指目标只是新生代的垃圾收集。

      • 老年代收集(Major GC/Old GC):指目标只是老年代的垃圾收集。目前只有CMS收集器会有单独收集老年代的行为。

      • 混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集。目前只有G1收集器会有这种行为。

    • 整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。

    标记-清除算法

    标记-清除算法(Mark and Sweep Algorithm)是一种经典的垃圾回收算法,用于识别和释放不再被引用的对象,从而回收内存空间。它包括两个主要阶段:标记(Mark)和清除(Sweep)。

    下面是标记-清除算法的工作原理:

    1. 标记(Mark)阶段
      • 从根对象(通常是程序的入口点或全局变量)开始,遍历整个对象图,标记所有可以从根对象访问到的对象。
      • 在这个阶段,被标记的对象通常被打上一个标记位或者加入一个"已标记"的集合中,以表示它们是活跃对象,仍然被引用。
    2. 清除(Sweep)阶段
      • 在清除阶段,垃圾回收器遍历整个堆内存,找到所有未被标记的对象,这些对象是不再被引用的对象。
      • 未被标记的对象被认为是垃圾,垃圾回收器会将它们的内存空间标记为可用空闲空间,以供将来的对象分配使用。
      • 清除后,堆内存中只剩下被标记的对象,而未被标记的对象的内存已经被释放。

    上面有一点需要注意的是,标记对象可以是所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象,也可以反过来,标记存活的对象,统一回收所有未被标记的对象。

    下面是标记-清除算法的示意图

    image-20230904194201368

    标记-清除算法的优点是它可以回收不再被引用的对象,但它也有一些缺点:

    • 碎片问题:标记-清除算法会在内存中留下不连续的空闲块,可能导致内存碎片化问题。这会增加分配大对象时的空间不足问题的风险。
    • 效率问题:标记-清除算法需要两次遍历整个堆内存:一次标记,一次清除。这会产生额外的性能开销,尤其是在清除阶段。
    • 停顿问题:标记-清除算法在清除阶段需要停止应用程序的执行,因为它需要整个堆内存处于不变状态才能执行清除操作。这可能导致应用程序在垃圾回收期间出现停顿,影响用户体验。

    标记-复制算法

    标记-复制算法(Mark and Copy Algorithm)是一种用于垃圾回收的算法,它解决了标记-清除算法中出现的内存碎片问题。标记-复制算法主要用于新生代(Young Generation)的垃圾回收,通常分为两个阶段:标记(Mark)和复制(Copy)。

    下面是标记-复制算法的工作原理:

    1. 标记(Mark)阶段

      • 从根对象(通常是程序的入口点或全局变量)开始,遍历整个对象图,标记所有可以从根对象访问到的对象,这些对象被认为是活跃对象。
      • 在这个阶段,被标记的对象通常被打上一个标记位或者加入一个"已标记"的集合中,以表示它们是活跃对象,仍然被引用。
    2. 复制(Copy)阶段

      • 在复制阶段,垃圾回收器会将所有被标记为活跃对象的对象从一个区域(通常称为"From"或"Eden"区)复制到另一个区域(通常称为"To"或"Survivor"区)。
      • 复制后,所有被复制的对象都连续排列在一起,没有碎片,而"From"区变成了空的。
    3. 清理(Clean-Up)阶段

      • 清理阶段不再需要被复制的对象,因此整个"From"区可以被清空,成为新的可用空间,用于将来的对象分配。

    示意图如下

    image-20230904195708455

    标记-复制算法的主要优点是它有效地解决了内存碎片问题。因为被复制的对象都被整齐地排列在一起,"From"区变为空,所以不会出现内存碎片化的情况。这提高了内存的利用率,减少了分配大对象时可能出现的空间不足问题。缺点就是比较浪费空间。

    标记-复制算法主要用于新生代的垃圾回收,而老年代通常使用其他算法,如标记-清除或标记-整理算法。这些不同的垃圾回收算法结合在一起,构成了现代Java虚拟机中的复杂垃圾回收策略,以提高内存管理的效率和性能。

    标记-整理算法

    标记-整理算法(Mark and Compact Algorithm)是一种用于垃圾回收的算法,通常用于老年代(Old Generation)的内存回收。它是标记-清除算法的改进版本,主要解决了标记-清除算法可能导致的内存碎片问题。

    相较于标记-清楚算法只是多了一个整理的过程

    整理(Compact)阶段

    • 在整理阶段,垃圾回收器会将所有被标记为活跃对象的对象向一端移动,以便它们连续排列在一起。同时,未被标记/被标记的对象都被认为是垃圾,不再需要,它们的内存空间会被释放。
    • 整理后,内存中的活跃对象变得更加紧凑,没有碎片,可以提高内存的利用率。

    示意图如下

    image-20230904200134998

  • 相关阅读:
    【JavaScript高级】ES6常见新特性:词法环境、let、const、模板字符串、函数增强、Symbol、Set、Map
    1004. 最大连续1的个数 III
    系统运维网络知识汇总
    关于队里面最菜的在博客打卡第六十二天这件事
    synchronized 关键字和 volatile 关键字有什么区别?
    mysql数据库的管理
    树莓派65/100 - Pico W初体验,点亮板载的LED灯
    【思维构造】Anonymous Informant—CF1894C
    打造 Web3 品牌灵魂三问:Why、What、How?
    ffmpeg2段视频合成一段
  • 原文地址:https://blog.csdn.net/m0_51545690/article/details/132676846