垃圾回收的三种算法
主要阐明垃圾回收算法的思想,而不对相关代码进行深究!
ps:其中引用计数法也属于垃圾回收算法中的一种,在java中是通过引用来和对象进行关联的,也就是说如果要操作对象,必须通过引用来进行。那么很显然一个简单的办法就是通过引用计数来判断一个对象是否可以被回收。不失一般性,如果一个对象没有任何引用与之关联,则说明该对象基本不太可能在其他地方被使用到,那么这个对象就成为可被回收的对象了。这种方式成为引用计数法。
这种方式的特点是实现简单,而且效率较高,但是它无法解决循环引用的问题,因此在java中并没有采用这种方式。
一、mark-sweep(标记-清除)算法
mark-sweep(标记-清除)算法,它分为“标记”和“清除”两个阶段:首先标记出所需回收的对象,在标记完成后统一回收掉所有被标记的对象,它的标记过程其实就是前面的可达性分析算法中判定垃圾对象的标记过程。标记—清除算法的执行情况如下图所示:
从图中可以很容易看出标记-清除算法实现起来比较容易,但是有一个比较严重的问题就是容易产生内存碎片,碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前触发新的一次垃圾收集动作。
二、copying(复制)算法
复制算法是针对标记—清除算法的缺点,在其基础上进行改进而得到的,它将可用内存按容量分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将还存活着的对象复制到另外一块内存上面,然后再把已使用过的内存空间一次清理掉。复制算法适合用于新生代
如下优点:
每次只对一块内存进行回收,运行高效
只需移动栈顶指针,按顺序分配内存即可,实现简单
内存回收时不用考虑内存碎片的出现
它的缺点是:可一次性分配的最大内存缩小了一半
三、标记—整理算法(mark-compact)
为了解决copying算法的缺陷,充分利用内存空间,提出了mark-compact算法。该算法标记阶段和mark-sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。具体过程如下图所示:
总结:
- 内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)
- 内存整齐度:复制算法=标记清除算法>标记压缩算法
- 内存利用率:复制算法<标记清除算法=标记压缩算法
在使用算法时候:
年轻代:
- 存活率低
- 复制算法
老年代:
- 区域大,存活率高
- 标记清除(内存碎片不是太多) 标记压缩共同实现