在进行垃圾回收之前,需要判断对象是否已死.一共有两种方法:
1.引用计数法
算法思想:给每个对象附加一个引用计数器,每当有一个地方引用此对象时,计数器加一,每当有一个引用失效时,计数器减一,在任意时刻只要计数器为0,该对象就是不能再使用的,即对象已死.
引用计数器实现简单并且判定效率较高,但是无法解决循环引用问题.(JVM并未采用此方法)
2.可达性分析算法
Java采用此算法来判断对象是否存活.
算法思想: 通过一系列"GC Roots"的对象作为节点,从这些节点开始向下搜索对象,搜索走过的路径,称为"引用链",当一个对象到任意一个GC Roots对象没有任何引用链相连时(从GC Roots到对象不可达),证明此对象已死.
在Java中,可作为GC Roots的对象包含下面几种:
- 虚拟机栈中引用的对象
- 类静态属性引用的对象
- 常量引用的对象
- 本地方法(Native方法)中引用的对象
JDK1.2之后对于引用的概念作了扩充,将引用分为强引用,软引用,弱引用,虚引用四种,这四种强度依次递减.
1. 强引用
强引用指的是在代码中普遍存在的,类似于Object obj = new Object();
在JVM中只要还有强引用的存在,该对象实例就永远不会被垃圾回收器所回收
2. 软引用
用来描述一些有用但不必须的对象,对于仅被软引用指向的对象,在系统将要发生内存溢出以前,会将所有的软引用对象进行垃圾回收,若内存够用,则这些对象仍然保留,在JDK1.2之后提供SoftReference实现软引用.
3. 弱引用
弱引用比软引用强度更差一点,仅被弱引用关联的对象最多只能存活到下一次GC开始之前.当垃圾回收器开始工作的时候,无论当前内存是否够用,都会回收掉仅被弱引用关联的对象,在JDK1.2之后使用WeakReference来实现弱引用.
4. 虚引用
虚引用也称为幽灵引用或者幻影引用,是最弱的一种关系,一个对象是否有虚引用的存在完全不会对其生存时间产生影响.也无法通过虚引用来取得一个对象实例,为一个对象设置虚引用的唯一目的就是在这个对象被GC之前,收到一个系统通知,JDK1.2之后提供PhantomRefrence来描述虚引用.
对象的自我拯救-finalize
protected void finalize() throws Throwable{
}
其实在可达性分析算法中不可达的对象,也并非"非死不可",所有不可达的对象处于"缓刑阶段",要宣告一个对象的彻底死亡,需要经历两次标记过程 :
若对象在进行可达性分析之后发现对象到GC Roots不可达,此对象对进行第一次标记并且进行一次筛选过程,筛选的条件是此对象是否有必要执行finalize().当对象没有覆盖finalize()或者JVM已经调用过finalize(),
JVM会将此对象彻底宣告死亡.
筛选成功(对象覆写了finalize()并且未被执行).会将此对象放入F-Queue,如果对象在finalize()成功解救(此对象与GC Roots建立联系),则对象会在第二次标记时被移除回收集合,成功存活,若对象在finalize中仍未与GC Roots建立联系(到GC Roots不可达