前言
上一篇我们对 JVM 的垃圾回收进行了探讨,知道了什么样的对象是垃圾对象,以及JVM 虚拟机是如何判断一个对象垃圾对象的,本篇我们来探讨一下 JVM 垃圾回收算法。
JVM 系列文章传送门
JVM 有哪些垃圾收集算法?
JVM 一共提供了四种垃圾回收算法,分别是标记-清除算法、标记-复制算法、标记整理算法和分代收集算法。
标记-清除算法
标记-清除算法是最简单干脆的垃圾回收算法,分为两个阶段,标记阶段和清除阶段,标记阶段 JVM 标记出所有需要回收的对象,清除阶段统一回收所有被标记的对象,它是最基础的收集算法,效率也很高,但是会带来两个明显的问题:
- 效率问题:需要遍历一遍内存空间,效率不高。
- 空间问题:会产生内存碎片,造成内存浪费,因为被回收的对象在内存中不是连续的空间,因此即使对象被回收后,空闲的空间同样是不连续的空间,假设 JVM 剩余的内存空间是 2MB,现在有一个 2MB 的对象需要被创建,JVM 的空间明明是够的,但是却无法容纳这个对象,这就是内存碎片占用不连续空间来带的问题。
标记-清除算法垃圾回收简图如下:
通过简图我们可以看到标记-清除算法回收完内存空间后,出现了大量的不联系的内存空间,这就会造成内存碎片问题。
标记-复制算法
因为标记-清除算法的一些问题,就有了标记复制算法,标记复制算法会先把内存空间分割成完全相同的两个区域,每次使用其中一个区域的空间,当这块区域内存使用完了的时候,将还存活的对象移动到另外一块区域去,然后把这块区域的对象一次性全部回收,这样每次回收的是整个内存空间的一半,一次循环运行。
标记-复制算法垃圾回收简图如下:
从简图上可以看到,标记-复制算法是先空出一半的内存区域,然后进行垃圾回收的时候会把另一半区域存活的对象全部复制到另一半区域,并且存活对象是连续的占用空间,标记-复制算法同样有它的优缺点,如下:
优点:
- 内存空间是连续的,解决了标记-清除算法的空间碎片问题。
缺点:
- 造成了空间浪费,因为每次只使用了一半的空间。
- 复制对象会造成性能损耗,标记复制算法多了复制对象的过程,是会有一些性能损耗的。
标记-整理算法
标记-整理算法是结合了标记-清除算法和标记-复制算法而来的,标记整理算法分为两个阶段:标记阶段和整理阶段,标记阶段还是遍历根节点(GC ROOTS)标记出对象,标记完成后并不是直接清理,而是整理,将所有存活的对象,按着内存地址一次排列,然后将末尾对象地址后面的内存全部回收,这就是标记-整理算法的整个过程。
标记-整理算法垃圾回收简图如下:
从简图可以看出标记-整理算法既没有浪费空间也没有内存碎片,看起来标记-整理算法完美,但其实并不是这样,接下来我分析一下标记-整理算法的优缺点,如下:
优点:
- 不会产生内存碎片。
- 不会浪费内存空间。
缺点:
- 标记-整理过程比较消耗时间,对于高并发的场景来说性能不够高。
标记-清除算法、标记-复制算法和标记整-理算法的比较
从算法回收内存消耗的时间上来看:标记-清除算法<标记-复制算法<标记-整理算法。
从回收的空间上来说看:标记-整理算法>标记-复制算法>标记-清除算法。
分代收集算法
分代收集算法严格意义上来将,其实不能算做一种算法,应该是一种思想,JVM 根据对象的生命周期将内存分为了年轻代和老年代,这样我们就可以根据年轻代和老年代的特点选用不同的垃圾回收算法,例如在年轻代又大量的对象快速死掉,我们可以选择标记-复制算法,只需要付出少量的复制成本就可以完成垃圾回收,而老年代都是都是存活比较久且存活概率比较高的对象,没有额外的空间进行完成复制,因此可以选用标记-清除算法或者是标记整理-算法。
目前所有的垃圾回收器几乎都采用分代手机算法执行垃圾回收的,基于分代的概念,GC 所使用的内存回收算法必须结合年轻代和老年代各自的特点。
总结:本篇分享了 Java 中的垃圾回收算法,只有理解了垃圾回收算法,才可以更好的理解 JVM 的垃圾回收机制和垃圾回收器的原理,希望可以帮助到有需要的朋友。
标签:标记,对象,回收,算法,垃圾,JVM From: https://blog.csdn.net/weixin_42118323/article/details/143661414