文章目录
- 一、标记清楚算法
- 二、标记复制算法
- 三、标记整理算法
- 四、不同垃圾收集算法优缺点总结
- 1. 标记-清除算法:
- 2. 标记-复制算法:
- 3. 标记-整理算法:
一、标记清楚算法
标记清除是一种简单而直接的垃圾回收算法。它的执行流程如下:当JVM标记出内存中的垃圾对象后,直接将其清除。然而,这种算法存在一个明显的缺点,即会导致内存空间的不连续,从而产生大量的内存碎片。
下图展示了标记清除算法执行后的内存空间示意图:
这里我们使用左侧的图来表示垃圾回收之前的内存状况,其中黄色区域表示可以被回收的垃圾对象。
这些对象在内存空间中不是连续的。
右侧的图表示垃圾回收后的内存情况,可以清楚地看到其中存在着断断续续的内存碎片。
然而,尽管垃圾已经被回收,但内存碎片仍然存在。你可能会问,那又有什么关系呢?毕竟内存碎片就是内存碎片嘛。
这里假设这些内存碎片所占用的总空间为1M,现在我们需要创建一个大小为1M的新对象。然而,不幸的是,尽管内存空间的总大小为1M,但并不是连续的。因此,我们无法将这个大对象存放在内存中。换句话说,这种情况必然导致内存空间的浪费,这就是内存碎片的危害。
如下图所示:
🎉优点:🎉
- 高效:垃圾回收不需要移动和复制对象。
🎉缺点:🎉
- 内存碎片:垃圾回收过程会导致内存碎片的产生,从而造成内存的浪费。
二、标记复制算法
由于标记清楚算法会产生大量的内存空间碎片问题,所以产生了标记复制算法:
复制算法是一种改进的垃圾回收算法,其工作原理如下:
首先将内存划分为两个区域。
新创建的对象都放在其中一块内存区域上。当该区域快要满的时候,就将被标记为存活的对象复制到另一块内存区域中(注意,这些对象在复制时在内存空间上是严格排序且连续的),这样就腾出了一半内存区域,使其变成了空闲空间。
然后,将所有的引用指向新的内存区域,并且清除原来的内存区域。这个过程不断循环运行。
在回收之前,将被标记为存活的对象复制到另一块内存区域。然后,回收垃圾对象,使其变成空闲空间,最终会变成下图:
如果再有新对象被创建,它将会被放置在右边的内存区域。当右边的内存区域满了之后,存活的对象会被复制到左边的内存区域,然后清除掉垃圾对象。
标记-复制算法的明显缺点是浪费了一半的内存空间,但优点是不会产生内存碎片。因此,在技术发展中常常会面临一个矛盾的抉择,即引入新技术必然会带来新问题。
到这里,我们来简单总结一下标记-复制算法的优缺点:
🎉优点:🎉
- 内存空间是连续的,不会产生内存碎片
🎉缺点:🎉
- 浪费了一半的内存空间
- 复制对象会导致性能和时间的消耗。
三、标记整理算法
标记-整理算法是综合了标记-清除算法和标记-复制算法的特点,并进行了演化而来的。
它的执行流程可以分为两个阶段:🎃标记阶段和整理阶段🎃
标记阶段: 与标记-清除算法相同,首先遍历GC Roots,并标记所有存活的对象。
整理阶段: 移动所有存活的对象,按照内存地址的次序依次排列,然后回收末端内存地址以后的内存空间。因此,第二阶段被称为整理阶段。
下面这张图是垃圾回收前的示意图:
下图表示的是标记-整理算法的第一阶段:标记并清除垃圾对象,同时标记出存活对象
接下来,来到第二阶段,整理碎片:
可以看到,通过标记-整理算法,我们既解决了内存碎片的问题,又充分利用了内存空间,避免了浪费。
然而,标记-整理算法在执行标记和整理的过程中会消耗大量的时间,尤其是在高并发的场景下,这可能会导致性能低下。
综上所述,标记-整理算法的优点是不会产生内存碎片和浪费内存空间,但缺点是执行时间较长,性能较低。
四、不同垃圾收集算法优缺点总结
1. 标记-清除算法:
优点:
- 不会产生内存碎片。
- 可以在有限的空间中进行垃圾回收。
缺点:
- 执行效率相对较低,因为需要遍历整个堆来标记和清除垃圾对象。
- 可能会导致内存碎片问题,因为垃圾对象所占用的空间无法被重用。
2. 标记-复制算法:
优点:
- 不会产生内存碎片。
- 执行效率相对较高,因为只需要遍历存活对象进行复制。
缺点:
- 浪费了一半的内存空间,因为需要将存活对象复制到另一半空闲的内存区域。
- 当存活对象较多时,复制的开销会增加。
3. 标记-整理算法:
优点:
- 不会产生内存碎片。
- 可以充分利用内存空间,避免浪费。
- 相对于标记-清除算法,整理过程可以提高内存分配的效率。
缺点:
- 执行效率较低,因为需要进行标记和整理的过程。
- 当存活对象较多时,整理的开销会增加。
🎈从时间长短的角度来看🎈 :标记-清除算法的执行时间较短,优于标记-复制算法,而标记-整理算法的执行时间最长。
🎈从结果来看🎈:标记-整理算法的效果稍逊于标记-复制算法,但优于标记-清除算法。
✨综合而言,可以得出以下结论:✨,不同的垃圾回收算法有各自的优缺点,选择合适的算法需要根据具体的场景和需求来决定。