垃圾回收算法-清除
# 一. 垃圾清除阶段
概述
成功区分内存中存活对象和死亡对象后,GC接下来的任务就是执行垃圾回收,释放掉无用对象所占用的内存空间, 以便有足够的可用内存空间为新对象分配内存。 JVM中常见的三种垃圾收集算法: 标记-清除算法(Mark-Sweep)、复制算法(Copying)、标记-压缩算法(Mark-Compact)。
# 1.1 标记-清除算法(Mark-Sweep)
# 执行过程
堆的有效内存空间被耗尽的时候,就会停止整个程序(也被称为stop the world),进行两项工作:
第一项则是标记
Collector(垃圾回收器)从引用根节点开始遍历,标记所有被引用的对象,一般是在对象的Header中记录可达对象
第二项则是清除
Collector (垃圾回收器)对堆内存从头到尾进行线性的遍历,如果发现某个对象在其Header中没有标记为可达对象,则将其回收。

# 优缺点
# 缺点
- 效率不算高
- 进行GC时需要停止整个程序,用户体验不好
- 清理后内存空间是不连续的,产生内存碎片
# 1.2 复制算法(Copying)
# 执行过程(核心思想)
将活着的内存空间为分两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中存活对象复制到未被使用到内存块中。 之后清除正在使用的内存块中所有对象,交换两个内存的角色。最后完成垃圾回收。

# 优缺点
# 缺点
- 需要两倍的内存空间
- 对于G1(JDK默认的GC)这种分拆成大量region的GC,复制而不是移动,意味着GC需要维护region之间对象引用关系,不管是内存占用或者时间开销也不小。
# 优点
- 没有标记和清除过程,实现简单,运行高效
- 复制过去以后保证空间的连续性,不会出现碎片问题
# 1.3 标记-压缩算法(Mark -Compact)
复制算法的高效性是建立在存货对象少,垃圾对象多的前提下的。这种情况多发生于 新生代 。但是在老年代更常见的情况是大部分对象都是存活对象。若依赖使用复制算法,由于存活对象较多,复制的成本也高,因此 基于老年代垃圾回收的特性,需要使用其他算法。
标记-清除算法的确可以应用在老年代中,但是该算法不仅执行效率低下,而且在执行完内存回收后还会产生内存碎片。所以JVM的设计者需要在此基础上进行改进-标记-压缩算法。

# 执行过程
第一阶段和标记-清除算法一样从根节点开始标记所有被引用对象。 第二阶段将所有的存活对象压缩到内存的一端,按顺序排放。之后清理边界所有空间。
# 优缺点
# 优点
- 消除标记-清除算法当中,内存区域分散的缺点。
- 消除了复制算法中,内存减半的高额代价。
# 缺点
- 效率上说,低于复制算法
- 移动对象的同时,如果对象被其他对象引用,则还需要调整引用地址。
- 移动过程中,需要暂停用户应用程序 即:STW
编辑 (opens new window)
上次更新: 2023/03/28, 16:13:29