垃圾回收算法
1、标记-清除算法
最基础的收集算法是“标记-清除算法”,分为标记和清除两部分,首先标记出所需要回收的对象,在标记万抽统一回收掉所有被标记的对象。
两个缺点:一是效率问题,标记和清除过程的效率都不高;另一个是空间问题,标记清除后会产生大量不连续的内存碎片,空间碎片太多可能导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
2、复制算法
将内存划分为大小相等得到两块,每次只是用其中的一块,当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
这样每次都是对一块内存进行回收,内存分配时也不用考虑内存碎片等复杂清理。实现简单,运行高效。内存浪费较大,只能使用一半的内存。
现在的商业虚拟机都是采用回收新生代,将内存分为一块较大的我Eden空间和两块较小的Survivor空间,每次使用Eden和其中的一块Survivor,当回收时,将Eden和Survivor中还存活的对象一次性地拷贝到另外一块Survivor空间上,最后清理掉刚才用过的Survivor的空间。HotSpot中Eden:Survivor=8:1。当Suvivor空间不够时,需要依赖其他内存进行分配担保。
3、标记-整理算法
复制算法在对象存活率较高时就要执行较多的复制操作,效率变低。所以老年代一般不直接选用这种算法。
所以提出了标记-整理算法,标记过程和“标记-清除”算法一致,后面是让所有存货的对象都向一端移动,然后直接清理掉端边界意外的内存。
4、分代收集算法
根据对象的存活周期的不同将内存划分为几块,一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法,新生代中使用复制算法,老年代中使用“标记-清除”或者“标记-整理算法”
5、堆的划分及回收过程
Eden区最大,对外提供堆内存;当Eden区快要满了,则进行Minor GC,把存活对象放入Survivor A区,清空Eden区;
Eden区被清空后,继续对外提供堆内存;
当Eden区再次被填满,此时对Eden区和Survivor A区同时进行Minor GC,把存活的对象放入Survivor B区,同时清空Eden和Survivor A区;
Eden区继续对外提供堆内存,并重复上述过程,即在Eden区填满后,把Eden区和某个Survivor区中存活的对象,放入另外一个Survivor区中;
当某个Survivor区被填满,且仍有对象未被复制完毕时或者某些对象在反复Survivor 15次左右时,或者某些相同年龄对象的个数大于某个Survivor的区大小的一半时,则把这部分对象放入到Old区;
当Old区也被填满时,进行Major GC,对Old进行垃圾回收。