垃圾收集算法

1.标记清除算法

最基础的清除算法是“标记-清除”(Mark-Sweep)算法,就如同它的名字一样,算法包括“标记”和“清除”两个阶段;在标记完成之后统一回收所有被标记的对象,之所以说它是最基础的算法,因为后续的算法都是基于这种思路并对其不足进行改进而成。

不足之处:

A.效率问题

“标记”和“清除”,两个阶段操作的效率都不高;

B.空间问题

标记清除之后会产生大量不连续的内存碎片,空间碎片太多会导致在以后程序运行中需要分配较大的对象时,无法找到足够的连续内存时不得不提前触发另一次垃圾收集操作。

标记清除算法示意图

2.复制算法

为了解决效率问题,就出现了“复制”(Copying)算法,它就内存按照容量等分为两部分,每次只使用其中的一块,当这一块的内存使用完毕之后,将还存活的对象复制到另一半内存上面,然后将已经使用的内存空间一次清理掉。这样使得每次内存回收都针对整个半区进行,不需要考虑内存碎片等复杂问题,只需要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效,只是内存的使用缩减到原来的一半,付出的代价太高。

复制算法示意图

3.标记-整理算法

复制算法在存活率较高的情况下,需要进行多次的复制,效率就会变低,如果不想浪费50%的空间,就需要有而外的内存空间进行担保,以应对内存所有对象都100%存活的极端情况,所以老年代一般不能直接使用这种算法。根据老年代的特点,有人就提出了“标记-整理”(Mark-Compact)算法,标记过程和“标记-清除”算法的标记过程一样,后续不是对可回收对象进行清理,而是让所有存活对象都向一端移动,而后直接清理端边界以外的内存

标记整理算法示意图

4.分代收集算法

当前商业虚拟机的垃圾收集机制都采用“分代收集”,一般将Java堆分为新生代和老年代,根据各个年代的特点采用适当收集算法;

“新生代”中每一次垃圾是收集时都有大量的对象死去,只有少量的对象存活,这时就可以使用复制算法;

“老年代”存活率较高,没有额外的空间对其进行分配担保,就可以选用“标记-清理”或者“标记-整理算法”。

你可能感兴趣的:(垃圾收集算法)