标记-清除算法(清除算法的基础)
将垃圾回收分为两个阶段:标记阶段和清除阶段。在标记阶段首先通过根节点,标记所有从根节点开始的对象,未被标记的对象就是未被引用的垃圾对象。然后在清除阶段,清除所有未被标记的对象。标记清除算法带来的一个问题是会存在大量的空间碎片,因为回收后的空间是不连续的,这样给大对象分配内存的时候可能会提前触发full gc。
复制算法(适用年轻代)
将现有的内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存空间的存活对象复制到未被使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。
现商业虚拟机都采用这种收集算法回收年轻代。---年轻代中的对象98%是朝夕生死的,所以并不需要按照1比1划分内存空间,而是将内存空间分为较大的eden和survivor空间,每次使用eden和其中一块survivor,当回收时,将eden和survivor中存活的对象复制到另一块survivor内存中,最后清理到eden和survivor中的对象。(默认比例8:1:1,也就是说每次使用的内存空间是90%,只有10%是被浪费,但同时无法保证回收只有不多于10%的对象存活,当survivor空间不够时,需要依赖其他空间进行分配保存---年老代)
标记-整理算法
复制的算法的高效性是建立在存活对象少,垃圾对象多的前提下。这种情况在年轻代经常发生,但是在老年代更常见的情况是大部分对象是存活对象。
标记-压缩算法是年老代的一种回收算法,他在标记-清除的基础上做了一些优化,首先也需要从根节点对所有可达的对象进行标记,随后并不是简单的清除,而是将所有存活对象压缩到内存一端。之后,清理边界外所有的空间。这种方法既避免了碎片的产生,又不需要两块相同的内存空间,因此,其性价比比较高。
增量算法
增量算法的基本思想是,如果一次性将所有的垃圾进行处理,需要造成系统长时间的停顿,那么就可以让垃圾收集线程和应用程序线程交替执行。每次,垃圾收集线程只收集一小片区域的内存空间,接着切换到应用程序线程。依次反复,直到垃圾收集完成。使用这种方式,由于在垃圾回收过程中,间断性地还执行了应用程序代码,所以能减少系统的停顿时间。但是,因为线程切换和上下文转换的消耗,会使得垃圾回收的总体成本上升,造成系统吞吐量的下降。