今天了解下垃圾回收的算法
1.标记-清除算法
分为“标记”和“清除”两个阶段,首先会标记出所有要回收的对象,在标记完成后统一回收所有被标记的对象。
缺点:
(1)标记和清除的过程效率都不高
(2)标记清除后产生大量的不连续的内存碎片,如果空间碎片太多的话,当程序需要分配较大内存对象时就无法找到足够大的内存而导致触发另一次垃圾回收
2.复制算法
复制算法是在标记-清除算法基础上改良而来,原理是将内存容量共分为大小相等的两块,每次只适用其中的一块,当一块的内存用完了,将还存活的对象复制到另一块内存上,然后将已适用过的内存全部清除。
优点:
- 每次只对一块内存进行回收,运行比较高效
- 只需要移动栈顶指针,按照顺序分配内存即可,实现起来比较简单
- 回收时不用考虑内存碎片的出现
缺点:
可一次性分配的最大内存缩小一半
现在的商业虚拟机都采用这种收集算法来回收新生代,新生代中的对象98%都是“朝生夕死”的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块比较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是说,每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的空间会被浪费。
当然,98%的对象可回收只是一般场景下的数据,我们没有办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖于老年代进行分配担保,所以大对象直接进入老年代。
3.标记-整理算法
复制算法比较适合于新生代,在老年代中,对象存活率比较高,如果执行较多的复制操作,效率将会变低,所以老年代一般会选用其他算法,如标记—整理算法。
标记过程与标记-清除算法的标记过程一样,标记后不是直接进想回收清理,而是让所有对象都向一端移动,然后直接清理掉端边界以外的内存。
4.分代收集
目前虚拟机的垃圾收集都采用分代收集,它根据对象的存活周期的不同将内存划分为几块,一般是把Java堆分为新生代和老年代。
在新生代中,每次垃圾收集时都会发现有大量对象死去,只有少量存活,因此可选用复制算法来完成收集
老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记—清除算法或标记—整理算法来进行回收