一、标记-清除算法
首先标记出算有需要回收的对象,标记结束后统一回收所有被标记的对象或者未被标记的对象;标记的过程就是判断对象是否属于垃圾的过程,使用引用计数法或可达性分析法
- 缺点
- 收集效率不稳定,java堆中包含大量的对象,其中大部分需要被回收,大量的标记、清除动作导致执行效率低
- 清除产生碎片空间,被清除的对象所处的内存空间不是连续的,这将导致产生大量的碎片空间,而这些碎片空间的大小不固定,当后续有大对象需要分配内存时,没有足够的内存
二、标记-复制算法
标记复制算法是为了解决标记清除算法执行效率低的问题,将内存空间划分为两块A、B,对象的分配在其中一块内存空间A,当堆中大部分对象需要回收时,将存活的对象复制到另外一块内存空间B,一次性将A中的对象回收
- 缺点
- 当大量对象存活时,大量内存间复制导致执行效率低
- 内存被划分为两块,每次只是用其中一块,造成空间浪费
但根据IBM公司针对新生代的研究-新生代中98%的对象熬不过第一轮收集,因此内存空间不必按照1:1划分,而是将新生代按照一定比例(Serial、ParNew等新生代收集器默认8:1)划分为一块较大的Eden区和两块较小的Survivor,每次分配只是用Eden区和其中一块Survivor区,垃圾收集时将存活对象复制到另一块Survivor区,这样内存就只有10%的新生代会被浪费,当存活对象大于10%时,通过‘分配担保’,复制到其它内存区域(大多数是老年代)
三、标记-整理算法
标记整理算法是为了解决对象存活率较高时要进行大量复制动作导致执行效率较低的问题,且不用浪费内存空间,相较于标记-复制算法将存活对象复制到另一块内存的动作,标记-整理算法将存活对象往内存的一端移动,然后直接清掉另一端的内存。这种收集算法适用于老年代区域,老年代对象通常不会轻易‘死掉’
- 缺点
- 移动存活对象并更新应用,必须完全暂停用户应用程序(‘stop the world’)才能进行