1.标记-清除算法
2.复制算法顾名思义,就是标记待GC的对象,然后清除掉。这算法有2个问题:效率问题:标记和清除的效率都不高。空间问题:因为清除之后会有大量的不连续内存,当分配大内存对象时可能没有空间供分配。
![]()
为了解决标记-清除算法的效率问题,复制算法是将内存分为等分的2块内存,1份使用,1份备份,当GC时就将还存活的对象复制到备份的内存,然后统一清除原本使用的另一块内存,这样效率提高了,不过将原本的内存分一半来做备份的代价太高了。
![]()
3.标记-整理算法由于分配50%的内存用作保留区域实在太浪费,所以目前更多的做法是分成80%(Eden区)+(10%+10%(survivor区)),这样只有10%的内存被浪费。因为新生代里的对象98%都是朝生夕死的,新创建的对象分配在eden区和有10%的survivor区,当GC的时候将还存活的对象存放到另一个survivor区,当然如果存活的对象在10%的survivor区不够放就会将对象移到老年代。![]()
![]()
这算法一般用在老年代GC收集里,标记需被回收的对象后统一向一端移动(整理),然后清除掉端边界以外的内存。
4.分代收集算法![]()
这个不是一个新算法,而是一个思想,一般JAVA堆被分为新生代和老年代,每个代都有符合自身的算法,比如新生代每次都是创建大量对象,GC后只需复制少量存活对象得成本就可以完成垃圾收集,所以就选择复制算法,老年代一般都是存活率高的对象且因为新生代还可以由老年代来担保分配内存(10%的survior区不足以存放新生代的存活对象),而老年代就没有担保了,所以就必须选择标记-清除或标记-整理算法。