1、 引用计数法
在每一个对象上记录这个对象被引用的次数,只要有任何一个对象引用了一次该对象,这个对象的计数器就+1,取消对这个对象的引用时,计数器就-1。任何一个时刻,如果该对象的计数器为0,则表明该对象可以回收。
2、 复制算法
将内存空间分为两块相同的存储空间,记为from区和to区,每次只使用一块。对象一开始只在From空间分配,To空间是空闲的。GC时把存活的对象从From空间复制粘贴到To空间,之后把To空间变成新的From空间,原来的From空间变成To空间。
- 好处:没有内存的碎片
- 缺点:会导致一半的to内存浪费。如果对象存活时间不长,这样通过轻GC清理from区的内存也就不会满,也就可以给to区,然后两个重复调用。而养老区的对象存活时间长,会导致内存不断叠加,这时候用复制算法会浪费内存空间(因为复制算法会空出一半to的内存)
3、 标记清除算法
标记清除算法对对象进行两次扫描。第一次扫描:标记。从根结点出发遍历对象,对访问过的对象打上标记,表示该对象可达。 第二次扫描:清除。对那些没有标记的对象进行回收,这样使得不能利用的空间能够重新被利用。
- 优点:不需要额外的空间
- 缺点:两次扫描,严重浪费时间,会产生内存碎片(碎片是因为空间不连续,有些大数据无法使用)
4、 标记压缩算法
标记压缩算法本质和标记清除算法差不多,只不过在清除阶段不一样。标记阶段和标记清除算法的标记阶段完全一样,主要通过遍历数次堆来进行压缩。压缩是清除的变体,压缩指的就是把存活对象重新装填一次,使对象都紧挨在一起,从而避免内存碎片的产生,同时保证内存的高速分配。
总结
内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)
内存整齐度:复制算法=标记压缩算法>标记清除算法
内存利用率:标记压缩算法=标记清除算法>复制算法
GC回收没有最优的算法,只有最合适的算法。我们可以使用分代收集算法使GC回收最优。即:
在新生区:存活率低,用复制算法
老年区:区域大,存活率高 用标记清除+标记压缩混合实现(调优:在进行几次标记清除后再一次标记压缩),碎片很多的情况下就标记整理压缩一次