1、引用计数法
为每个对象添加一个计数器,每经过一次GC且存活,则计数器+1
适用于老年区,因为计数器的使用既占空间又费时间,不应为大量变动的对象使用此方法,因此不适用于新生区和幸存区。
一般不使用此方法。但是Python似乎是用的这个办法,因此效率低。
2、复制算法
每次进行一次轻GC的时候,将Eden区和from区幸存的对象复制到to区,然后动态改变to区(因为谁是空的,谁就成为to区)
优点:无碎片化内存空间
缺点:to区必然是空的,因此浪费一份空间。
适用于青年区,但不适用于幸存区存在过多的对象,假设from区已经满了,进行GC的时候,需要把from的对象全部复制到to区,然后from变成to,这个动作耗费是很大的。
3、标记清除法
扫描一次全部对象,给需要保留的对象添加标记;
再扫描一次全部对象,把没有标记的对象删除。
优点:不需要浪费空间
缺点:会导致内存碎片,且两次扫描严重浪费时间
4、标记压缩法
再优化:防止内存碎片产生
再次扫描,向一段移动存活的对象。
多了一个移动成本,但是不会产生内存碎片
3和4经常统称为标记压缩清除算法。
继续优化
可以先执行五次轻GC的标记清除,再执行一次标记压缩,这样可能会稍微好一点。
总结
内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)
内存整齐度:复制算法=标记压缩算法> 标记清除算法
内存利用率:标记压缩算法=标记清除算法>复制算法
没有最好的算法,只有最合适的算法。时间复杂度和空间复杂度是相斥的。
GC:分代收集算法
年轻代:
存活率低---->复制算法
老年代:
区域大、存活率高---->标记清除(内存碎片不是太多的时候,就先不压缩)+标记压缩混合实现