标记-清除算法
标记-清除算法(Mark Sweep )是很多垃圾回收算法的基础,分两个步骤:
- 标记:遍历所有的GC Roots,并将GC Roots可达的对象设置为存活对象
- 清除:遍历堆中所有对象,将没有被标记可达的对象清除
标记清除算法执行过程中会产生“stop the world”。因为如果不暂停Java程序,在标记完成后又新产生了一个对象,而该对象已经错过了标记期,那么在接下来的清除流程中会被视为不可达对象而被清理。
优点
基于最基础的可达性分析算法,是最基础的收集算法
缺点
标记清除后会产生大量不连续的内存碎片,每次分配都需要遍历空闲列表找到足够大的分块;在分配大内存对象时,无法找到足够的连续内存,从而触发另一次垃圾收集动作
复制算法
复制算法(Copying)简单来说就是将内存一分为二,但只使用其中一份,在垃圾回收时,将正在使用的那份内存中存活的对象复制到另一份空白的内存中,最后将正在使用的内存空间的对象清除,完成垃圾回收
优点
- 每次都只对整个半区进行内存回收
- 内存分配时不用考虑内存碎片等问题,可使用“指针碰撞”的方式分配内存
缺点
- 空间浪费:内存缩减为原来的一般
- 效率问题:当对象存活率较高时,需要进行较多复制操作,效率将会变低
标记-整理算法
标记-整理算法(Mark Compact)又称标记-压缩算法,该算法标记阶段和 Mark-Sweep 一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。
优点
有效利用了堆,不会出现内存碎片,也不会像复制算法那样只能利用堆的一部分
缺点
- 压缩过程的开销大,需要多次搜索堆
- 需要“stop the world”
分代收集算法
分代收集算法(Generatinal Collection)是目前大部分 JVM 的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干不同的区域,一般将堆区划分为老年代(Tenured Generation)和新生代(Young Generation)。
-
年轻代 采用 复制算法
新生代中每次垃圾回收都要回收大部分对象,需要复制的操作次数较少
一般来说将新生代划分为一块较大的 Eden 区和两块较小的 Survivor 区,每次使用 Eden 区和其中一块 Survivor 区。当进行回收时,将 Eden 和 Survivor 中还存活的对象复制到另一块 Survivor 空间中,然后清理掉 Eden 和刚才使用过的 Survivor 区。 -
老年代 使用 标记-整理算法
老年代是年轻代筛选出来的对象,被标记比较高,需要删除的对象比较少,采用标记-整理效率较高
网友评论