

JVM常见的垃圾回收算法
source link: https://segmentfault.com/a/1190000041140536
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1、Mark-Sweep 标记-清除算法
算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象,也可以反过来,标记存活的对象,统一回收所有未被标记的对象。标记过程就是对象是否属于垃圾的判定过程。
缺点:
(1)执行效率不稳定:
如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低;
(2)内存空间的碎片化问题
标记、清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
2、Copy 拷贝算法
标记-复制算法常被简称为复制算法。为了解决标记-清除算法面对大量可回收对象时执行效率低的问题,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。如果内存中多数对象都是存活的,这种算法将会产生大量的内存间复制的开销,但对于多数对象都是可回收的情况,算法需要复制的就是占少数的存活对象,而且每次都是针对整个半区进行内存回收,分配内存时也就不用考虑有空间碎片的复杂情况,只要移动堆顶指针,按顺序分配即可。
缺点:
(1)浪费空间
缺陷也显而易见,这种复制回收算法的代价是将可用内存缩小为了原来的一半,空间浪费未免太多了一点。
3、Mark-Compact 标记整理算法
其中的标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。
缺点:
(1)修改引用耗费资源
整理阶段移动存活对象并更新所有引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动操作必须全程暂停用户应用程序才能进行。
根据各个算法的特点也可以得知:在新生代存活对象少的情况下,使用Copy算法;在老年代或存活对象多的情况下,使用Mark-Sweep、Mark-Compact算法。
G1之前分代垃圾收集器的新生代,Serial、ParNew等收集器均采用Copy算法设计新生代的内存布局;Parallel Scavenge收集器是基于标记-整理算法的,而关注延迟的CMS收集器则是基于标记-清除算法。
4、三色标记算法
G1和CMS里都有一个并发标记垃圾的过程,也就是此时GC线程和工作线程是同时工作的,也就是会出现非垃圾变为垃圾(此时直接在下次回收时清理掉就可以,并没有大的影响)、垃圾变为非垃圾的情况,而垃圾变为非垃圾时如果没有及时发现处理而被回收了,那么会产生非常严重的后果,JVM是采用三色标记算法来解决这种问题的。
把遍历过程中遇到的对象,按照“是否访问过”这个条件标记成以下三种颜色:
(1)白色:表示对象尚未被垃圾收集器访问过。
(2)黑色:表示对象已经被垃圾收集器访问过,且这个对象的所有引用都已经扫描过。黑色的对象代表已经扫描过,它是安全存活的,如果有其他对象引用指向了黑色对象,无须重新扫描一遍。黑色对象不可能直接(不经过灰色对象)指向某个白色对象。
(3)灰色:表示对象已经被垃圾收集器访问过,但这个对象上至少存在一个引用还没有被扫描过。
当且仅当以下两个条件同时满足时,会产生错误回收的问题,即原本应该是黑色的对象被误标为白色:
1、赋值器插入了一条或多条从黑色对象到白色对象的新引用;
2、赋值器删除了全部从灰色对象到该白色对象的直接或间接引用。
因此,我们要解决并发标记的这个问题,只需破坏这两个条件的任意一个即可。由此分别产生了两种解决方案:增量更新(Incremental Update)和原始快照(Snapshot At The Beginning, SATB)。
1、增量更新要破坏的是第一个条件,当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。
这可以简化理解为,黑色对象一旦新插入了指向白色对象的引用之后,它就变回灰色对象了。
2、原始快照要破坏的是第二个条件,当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根,重新扫描 一次。
这也可以简化理解为,无论引用关系删除与否,都会按照刚刚开始扫描那一刻的对象图快照来进行搜索。
在 HotSpot虚拟机中,增量更新和原始快照这两种解决方案都有实际应用,譬如,CMS是基于增量更新来做并发标记的,G1、Shenandoah则是用原始快照来实现的。
Recommend
-
39
-
79
JVM的GC经过多年的发展,大家对 Minor GC、 major GC的理解并不完全一致,所以我不打算在本文中使用这个概念。我把GC大概分为一下4类: Young GC:只是负责回收年轻代对象的GC; O...
-
60
前言 java相较于c、c++语言的优势之一是自带垃圾回收器,程序开发人员不用手动管理内存,内存的分配和释放完全由gc(Garbage Collector)来做,极大地提高了软件开发效率及程序健壮性(手动管理内存容易造成内存泄漏)。凡事皆有...
-
46
整理了JVM垃圾回收的一些问题 为什么Young Generation适合使用复制算法 一句话:因为YGen的特点是大批对象快速死去,仅有少量对象存活。对于复制算法来说,每次复制的内容并不多,成本较低。 为什么是复制...
-
25
Java 中的垃圾回收,常常是由 JVM 帮我们做好的。虽然这节省了大家很多的学习的成本,提高了项目的执行效率,但是当项目变得越来越复杂,用户量越来越大时,还是需要我们懂得垃圾回收机制,这样也能进行更深一步的优化。 <!--...
-
18
垃圾回收与内存分配策略 垃圾回收与内存分配策略 “垃圾”的定义 对象是否为“垃圾” 判断对象是否已成为“垃圾”的两种方法: 引用计数法 、 可达性分析算...
-
12
JVM 的自动内存管理,让原本应该是开发人员去做的事情,变成了垃圾回收器来做的事情既然是别人帮忙做的事情,那么可能就不是自己想要的,所以就需要我们了解一下垃圾回收相关的内容 引用计数法与可达性分析垃圾回收,垃圾回收,那就是有...
-
6
开往虚拟机的车已经出发,关注上车 那些回收 JVM 垃圾的家伙 ❝
-
8
背景 在Java中有一个很重要的概念,即 一切皆对象
-
3
介绍JVM内存回收机制。对什么区域进行垃圾回收? 栈是线程私有的,所有不进行回收。 查看GC回收情况:-XX:+PrintGC。 查看GC回收详情:-XX:+PrintGCDetails。 一、什么情况下回收? ...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK