`

Java垃圾收集之垃圾收集算法

 
阅读更多

几种基本的垃圾收集算法

 

标记-清除算法 

        顾名思义,此方法涉及到两个步骤:标记和清除。首先标记出所有需要回收的对象,在标记完成后统一完成回收。标记的过程在《Java垃圾收集之对象引用》中已经介绍过。此方法是最基础的垃圾收集算法,后续的收集算法均基于此方法改进而得来。

        它的缺点主要有两个,一个是效率问题,标记和清理的过程执行效率都不高;第二是清理过后容易产生很多不连续的内存空间,即内存碎片。太多的内存碎片,会导致在分配占用大量内存空间的对象时候没有足够的连续内存而不得不提前触发另一次垃圾收集动作。

 

复制算法

        为了解决上述算法的效率问题,复制算法出现了。它将可用的内存空间分为大小相同的两块,每次只使用其中的一块内存区域,当这快内存区域使用完时,就将存活的对象复制到另一块内存空间中,然后再把使用过的内存空间一次清理干净。

        这样,每次都是对其中的一块区域进行回收,内存分配时也不用考虑内存碎片问题,只要顺序移动堆顶指针,按序分配内存即可,简单高效。

        缺点也很明显,可用内存缩小为原来的一半。

        现代的商业虚拟机都采用此法来回收新生代,由于新生代中的对象一般情况下98%都是朝生夕死的,所以并不需要按照1:1的比例划分空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间。每次使用Eden和其中的一块Survivor空间。HotSpot虚拟机按照8:1的空间分配Eden与Survivor空间,也就是说,只有10%的空间是被浪费的。

        当Survivor空间不足时(并不一定每次存活的内存都在10%以内),需要向其他内存空间今夕功能分配担保(Handle Promotion)。

 

标记-整理算法

        复制算法只能在对象存活率较低的情况下有良好的性能表现,但在对象存活率较高的情况下就不适用了,原因是要进行大量的对象复制操作。更关键的是,如果对象存活率高,那么就不得不浪费50%的内存空间来应对对象100%存活的极端情况。所以,在老年代中,一般不采用此方法进行垃圾回收。

        所以,在老年代中,采用的垃圾收集算法是“标记-整理”算法。标记过程和“标记-清除”算法中的标记过程相同,但后续的步骤是将存活的对象向内存的同一端移动,然后直接清理掉剩余的部分。

 

分代收集算法

        当前商业虚拟机的垃圾收集器都采用“分代收集(Generational Collection)”算法,根据对象存活周期的不同而将内存划分为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点来采用不同的垃圾收集策略。新生代由于对象存活率低,采用复制算法,只要付出复制少量存活对象的代价就可以完成垃圾收集。而老年代由于对象存活率高,标记整理或者标记清除算法就更加适合。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics