1.标记阶段的目的
主要是在GC在前,判断出哪些是有用的对象,哪些是需要回收的对象,只有被标记为垃圾对象,GC才会对其进行垃圾回收。判断对象是否为垃圾对象的两种方式:引用计数算法和可达性分析算法。
2.引用计数算法(现在不再使用)
引用计数算法实现相对比较简单,就是给每一个对象保存一个引用计数器,记录此对象被引用的次数。只有该对象的引用次数为0,才表示该对象不在被使用,即可回收。
优点:便于实现,回收及时,判定效率高。
缺点:
-
因为要有引用计数器,所以需要额外的空间。
-
每次的操作都要个计数器重新赋值,所以需要额外的时间。
-
(重点)无法处理循环引用的问题,比如说外部P引用了A,而A引用了B,B又引用了C,C又引用了A,那么对于A,B,C其计数器为2,1,1,那么此时如果外部引用P赋值为null,及无外部引用了,但是A,B,C计数器依然为1,无法被回收,常此就会出现内存泄露。
3.可达性分析算法(也称为根搜索算法、追踪性垃圾收集)
可达性算法可以解决循环引用的问题,其思路为以根为起始点向下搜索,存活的对象就是与根直接或者间接相连的对象,所搜索经过的路径称为引用链,如果未被搜索到,则表明不可达,就标记为垃圾对象。
那么要作为根的判断标准是什么呢?
-
虚拟机栈中引用的对象(如局部变量...)。
-
方法区中类的静态变量。
-
被同步锁synchronized持有的对象。
-
Java虚拟机内部的使用。
4.对象的finalization机制
finalize()方法机制,是指对象被回收前由GC调用的方法,只会调用一次,Java提供了对象被销毁前允许开发人员来自定义销毁前要做的事情,finalize()方法是Object类中的方法,此方法内没有任何的实现,开发人员可以重写该方法。不要主动的去调用finalize()方法。因为:
-
finalize()方法可以使对象不在被销毁,在临死前拉一把。
-
如果不发生GC,finalize方法是没有执行机会的。
-
一个糟糕的finalize()可能会使程序崩溃,比如里面自定义一个死循环。
5.由于finalize(),对象的三种状态
-
可触及的,及可从根到达此对象。
-
可复活的,对象被标记为垃圾,但是可能在finalize()方法中被拯救。
-
不可触及的,对象的finalize()方法被调用了,并且没有复活。
具体的过程:一个对象要被回收,要经历两次标记的过程,如果此对象没有任何的引用,则会被标记为垃圾对象,等待回收,在回收前,执行该对象的finailze()方法,如果没有重写该方法,对象就会为不可触及状态被清理,如果重写了该方法,则会被加入到队列中,由一个Finalizer低优先级的线程来执行,如果在方法中没有补救,那么第二次标记就会标记该对象将会彻底被回收清理,如果在finalize()方法中对象又建立了联系,那么此对象又会进入可触及的状态,如果又没有了引用,finalize()方法不会在被调用(只会调用一次),对象直接会变为不可触及的状态。