垃圾回收算法
标记-清除算法
- 分为两个阶段:“标记”和“清除”;
- 首先标记出需要所有需要回收的对象;
- 标记完成之后,统一收回所有需要回收的对象。
缺点: - 效率问题:标记和清除两个过程的效率都不高;
- 空间问题:回收之后,会导致空间不连续,碎片太多。如果之后有一个大的对象,无法连续的空间会导致无法分配内存,触发垃圾收集动作。
复制算法
- 将内容化为两部分,一块称为(A),另外一个为(B);
- 每次只使用A块,来进行存储;
- 如果A的内存使用完,将A的需要存活对象复制到B中;
- 然后将A中的垃圾进行清理;
缺点: - 只能使用原来内存的一半。
标记整理算法
- 首先想前面讲述的“标记-清除算法”,首先进行标记;
- 然后将所有存活的对象都移向一端;
- 最后直接清除掉边界以外的内存
分代收集算法
- 因为大多数的对象都是朝生夕死,所以将堆划分为两块“新生代”和老年代
- 新生代中有两块内容:Eden区和Survivor区,Survivor分为两部分:S0,S1
- 刚开始,对象会直接分配到Eden区,S0,S1此时为空;
- ① 随着对象的分配,Eden区首次存满,触发YGC;
- 标识出Eden区垃圾对象,将需要存活的对象分配到S0区,将Eden区清空;
- 此时Eden区空,S0有对象,S1空;
- ② 随着对象的分配,Eden区在次存满,触发YGC;
- 标识出Eden区和S0的垃圾对象 ,(此时S0中含有垃圾对象),将需要存活的对象分配到S1区;
- 此时Eden区空,S0空,S1有对象
- 随着对象的分配,Eden会在此存满对象,就会重复刚刚②的过程。
- 和②不同的是,将S1和Eden区的对象分配到S0区;S1为空
- 就这样往复分配。
- 有一些对象,存活的时间比较长,这样会占一定的开销,所以对对象会标记年龄。
- 每次从一个区转到另外一个区就会年龄+1;
- 一直到年龄足够大的时候(默认为15),就将对象放到老年代中。
- 大对象直接进入到老年代(需要大量的连续空间)
- 如果老年代区满了之后,会触发FGC(标记-整理算法)
七种垃圾回收器
年轻代垃圾收集器
Serial收集器
- 单线程垃圾收集器
- 标志-复制算法
- 会发生STW(Stop The Word)
ParNew 收集器
- 多线程垃圾收集器
- 同样会发生STW
Parallel Scavenge收集器
- ParNew的升级版,同样是多线程收集器
- 吞吐量优先
老年代垃圾收集器
Serial Old收集器
- 单线程垃圾收集器
- 标志-整理算法
- 会发生STW(Stop The Word)
ParNew Old 收集器
- Serial Old收集器的多线程垃圾收集器版本
- 同样会发生STW
CMS收集器(Concurrent Mark Sweep)
- 并发多线程收集器
- 分为四个阶段:
- 初始标记:主要标记GCroot 的下一级对象。(期间会有STW)
- 并发标记:根据上一步标记的对象,进行继续向下标记所有关联的对象,一直到尽头。
- 期间没有STW,是多线程的过程,耗时较长。
- 重新标记:在使用用户线程时可能会出现一些新的垃圾对象,对这些对象进行标记。期间有STW。
- 并发清理:和用户线程进行多线程的清理。此时会以标记-清除算法进行垃圾清除。在此期间用户线程可能会有新的垃圾,只能等到下一次的GC。
- CMS和parNew Old的对比图
缺点:
- 在并发阶段不会导致用户线程的停顿,但是由于占用了一部分线程导致应用程序变慢,吞吐量降低。
- 无法处理浮动垃圾。浮动垃圾:在并发清理阶段,用户线程会有新的垃圾出现,但是CMS只能下一次处理。
- 在垃圾回收阶段用户还需要运行,所以需要预留一定的空间给用户线程,所以不能等到老年代几乎被填满才能进行垃圾收集。
- 因为使用的是标记-清除算法,所以会存在标记清除算法的缺点。
G1 收集器(Garbage First)
G1收集器相对于之前的垃圾收集器的特点:
-
并行与并发:
- 并行:G1能充分利用多CPU,缩短STW的时间。
- 并发:部分垃圾收集器,需要停顿线程来进行GC动作,但是G1可以通过并发的方式继续执行线程,不会在整个回收阶段发生完全的阻塞。
-
分代收集:
- 仍然拥有分代的概念,但不要求整个Eden区,Survivor区,老年代的空间连续,也不坚持固定大小和固定数量。
- G1可以独立管理整个GC堆,不需要搭配其他垃圾收集全去管理GC堆。
- G1可以独立管理整个GC堆,不需要搭配其他垃圾收集全去管理GC堆。
- 仍然拥有分代的概念,但不要求整个Eden区,Survivor区,老年代的空间连续,也不坚持固定大小和固定数量。
-
空间整合:
- G1将内存划分为一个一个的region,内存的回收是以region作为基本单位的。
- G1整体看起来是基于“标记-整理”算法的收集器,但从局部(两个region之间)上,看起来是基于复制算法来实现的。优点是这两个算法在运行期间都不会产生内存空间碎片。不会因为对象过大,而不得已触发下一次的GC。
-
可预测的停顿的时间模型:
- G1不仅追求低停顿,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒。
- 由于分区 的原因,G1可以只选择部分的区域进行内存回收,这样缩小回收的范围,因此对于全局停顿情况的发生也能够得到较好的控制
- G1每次优先回收价值最大(回收所获得的空间大小以及回收所需要时间的经验值)的Region,保证了G1收集器在有限的时间内可以获取尽可能高的收集率。