垃圾收集首先最重要的是要确定:对象是否已经死亡
判定对象是否已经死亡的算法主要分为两种:
1、引用计数算法:
给对象添加一个引用计数器,只要有其他的对象应用它就给计数器+1,当引用失效以后就给计数器-1,所以当计数器的值为0的时候,就表示不可能再被使用。
优势:实现简单、判定效率也高
弊端:它不能解决对象之间的相互循环引用,例如:A对象引入B对象,而B对象也引入A对象,除此之外A和B对象就再无其他被引用,可是A和B的引用计数器却不为0,就无法回收。
2、可达性分析算法:
通过一系列的“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为“引用链”,当一个对象到“GC Roots”没有任何引用链相连的时候,则说明对象不可用,可以回收。
以上两种算法为初步判定对象可以进行回收,并不是一定就会回收;好比刚开始这些对象已经被判刑,需要等待执行,等待执行中如果有对象重新被引用或者重新通过引用链和“GC Roots”节点取得了连接,那么就不能对这个对象进行回收。
当对象通过可达性算法发现不可达,即对象发现没有与“GC Roots”通过引用链进行相连后,就进行一次标记并且进行一次筛选,筛选的条件是看对象是否覆盖了finalize()方法,如果没有finalize()方法或者虚拟机已经执行过finalize()方法,则认为对象“没有必要执行”稍后等待真正回收;如果覆盖了并且虚拟机还没有执行finalize()方法,则进行第二次标记,会吧对象放到一个queue里面,然后由虚拟机自动建立的一个线程去执行这个队列里面对象的finalize()方法,如果在执行过程中对象重新与“GC Roots”建立的了引用,那么该对象就会顺利逃脱拯救自己被回收的命运,反之对象被二次标记等待真正的回收。(注意:对象的finalize()方法只能执行一次)
**垃圾回收的算法
1、标记-清除算法
这个算法是最基础的搜集算法,主要分为两个阶段:标记和清除。首先标记出哪些需要回收的对象,当标记完成后,统一对标记的对象进行回收。
弊端:效率低、空间产生大量不连续的碎片
2、复制算法
这个算法是将可用内存划分为大小相等的两块,其中一块用来使用,当这块内存用完以后,就将这块内存中还存活的对象复制到另外一块中去,然后清除使用的那块内存。
优势:效率高、实现也简单
弊端:缩小了可使用的内存空间
3、标记-整理算法
标记整理算法和标记清除算法类似,只不过后面流程有些区别,它是将还存活的对象统一移动到一端,然后再统一清理掉端外的内存空间
4、分代收集算法
基本上都采用这个算法,其实这个算法没有新的思想,就是根据对象的存活周期将内存划分为几块,java堆划分为新生代和老年代,这样根据不同的代进行不同的算法,新生代采用复制算法,老年代采用标记整理或者标记清理算法