垃圾收集器(Garbage Collection, GC)的诞生引导出了三个问题:
哪些内存需要回收?
什么时候回收?
如何回收?
对于线程独占的三个区域(程序计数器、虚拟机栈、本地方法栈)不用过多的考虑垃圾回收的问题,因为他们随着线程创建而生,随着线程结束而消失。然而Java堆和方法区则不一样,一个接口的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也不一样,我们只有在程序运行的的时候才知道会创建哪些对象,这部分的内存分配是动态的,所以这也是GC所关注的方面。
如何判断对象已死
(1)引用计数法:给对象添加一个引用计数器,每当一个地方引用它,就加一,引用失效,就减1。引用计数法实现比较简单,判定效率也高,但是往往有这样一种情况,两个对象相互引用,除此之外别无它用,这样算不算垃圾对象?在经过验证之后发现,这样的对象也会被GC回收,因此我们可以判定,Java虚拟机的GC采用的并不是这种机制。
(2)可达性分析法:这个算法的基本思想就是通过一系列的称为“GC Roots”的对象作为起始点,从这些结点开始向下搜索,搜索走过的路径称为引用链。当一个对象没有任何引用链相连时,我们可以得到这个对象是不可用的,于是这个对象会被判定是可回收的对象。
生存还是死亡
即时在可达性分析法中不可达的对象,也并非是“非死不可”的对象,这时候他们暂时处于一个“缓刑”状态,要想真正的宣告一个对象的死亡,至少经历两个标记过程:如果对象不可达,那么它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法,如果(1)没有这种方法(2)已经执行过这种方法,那么就可以看做“没有必要执行”。如果对象被判定有必要执行finalize方法,那么这个对象将会被放在一个叫F-Queue的队列之中,并在稍后由一个虚拟机自动建立、低优先级的Finalize线程去执行它。如果对象在这次处理中拯救了自己,和其他建立了联系,那么就会被移除“即将回收”集合。如果还是没有任何联系,那就会被真正回收掉。