1.标记-清除算法
对所有存活对象进行一次全局遍历来确定哪些对象可以回收,遍历的过程从根出发,找到所有可达对象,除此之外,其它不可达的对象就是垃圾对象,可被回收。整个过程分为两个阶段:标记阶段找到所有存活对象;清除阶段清除所有垃圾对象。
优点:采用的可达性分析算法,相比较引用计数算法,标记-清除算法可以非常自然的处理循环引用问题,另外在创建对象和销毁对象时时少了操作引用计数值的开销。
缺点:1.标记-清除算法是一种“停止-启动”算法,在垃圾回收器运行过程中,应用程序必须暂时停止。
2.效率问题:标记-清除算法在标记阶段需要遍历所有的存活对象,会造成一定的开销,清除阶段,由于空闲区域特别多,要维护的空闲表也很大,效率也不高。
3.碎片问题:标记-清除算法会在垃圾回收后产生大量碎片,以后分配大对象时无法找到足够的连续内存,而不得不提前触发下一次垃圾收集动作。
2.复制算法
复制算法是把整个堆分成两个半区(From,To),每次只用其中一块,当一个半区用完后就进行一次垃圾回收, GC的过程其实就是把存活对象从一个半区拷贝到另外一个半区,并把已使用过的内存空间完全清除一次的过程,而在下一次回收时,两个半区再互换角色。在移动结束后,再更新对象的指针引用。
优点:1.每次回收都是一半区的整体回收该考虑,不用考虑碎片问题。
2.只需要移动堆顶指针按顺序分配内存,实现简单,运行高效。
缺点:1.浪费空间换时间,存在一半的内存浪费;2.存货对象较多时,复制是比较低效的。
注:实际上商业虚拟机都是这样来回收新生代,由于对象中98%都是很快死亡,撑不过下次回收之前,因此并不是按照1:1这样来划分内存空间,将内存 分为一块较大的Eden和两块较小的Survivor空间,每次使用Eden和其中一块Survivor,回收时将Eden和其中一块在用的Survivor内存中的东西复制到另一 块未用的Survivor内存。一般Eden:Survivor为8:1,这样只有10%内存浪费。但是并不是所有的情况都满足于只有不多于10%的内存存活,因此当 Survivor内存不够时需要依赖其他内存(这里指老年代)进行分配担保(Handle Promotion)。
3.标记-整理算法
根据老年代特点,提出了“标记-整理算法”(Mark-Compact)。标记-整理算法和标记-清除算法的标记过程是一致的,而后续动作则是让所有存活对象向一端移动,然后直接清理掉端边界以外的内存。
4.分代收集算法
现在商业虚拟机的垃圾收集都采用“分代收集”(Generational Collection)算法,根据对象存货周期的不同将内存划分为几块,一般分为新生代和老年代,新生代由于对象存活时间短,采用复制算法,老年代由于对象存活率高、无额外空间对他进行分配担保,因此采用标记整理或者标记清除算法来进行回收。