在堆里存放着Java几乎所有的对象实例,垃圾收集器在对堆内存进行回收前,首先得确定这些对象是否还存活(是否有被引用)。主流的判断方法有两种算法:引用计数算法和可达性分析算法。
引用计数算法
引用计数是最简单直接的一种方式,这种方式在每一个对象中增加一个引用的计数,每当某一个对象被别的地方引用就把他的引用计数器加上1,如果此对象的引用计数变为0,那么此对象就可以作为垃圾收集器的目标对象来收集。Python语言使用的就是此种算法。
优点:简单,直接,不需要暂停整个应用
缺点:不能处理对象循环引用的问题
可达性分析算法
在主流的商用语言(如Java,C#等)中采用的是可达性分析算法进行垃圾回收,通过一系列的名为“GC Roots”的对象作为起点,从这些节点向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Root没有任何引用链相连时,则该对象不可达,该对象是不可使用的,垃圾收集器将回收其所占的内存。
在java语言中可作为GCRoots的对象包括以下几种对象:
- java虚拟机栈(栈帧中的本地变量表)中的引用的对象。
- 方法区中的类静态属性引用的对象。
- 方法区中的常量引用的对象。
- 本地方法栈中JNI本地方法的引用对象。
对象引用
判断对象是否可活都离不开引用,引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)四种,这四种引用强度依次逐渐减弱。
1)强引用是指程序代码中普遍存在的,类似“Object obj = new Object()”这类的引用,只有强引用还存在对象就绝不会被回收。
2)软引用软引用是用来描述一些还有用但是非必需的对象。对于软引用关联的对象,在系统将于发生内存溢出异常之前,将会把这些对象列进回收范围中进行二次回收。
3)弱引用也是用来描述非必需对象的,强度比软引用还弱一些,被软引用关联的对象只能存活到下一次垃圾收集发生之前。
4)虚引用也称为幽灵引用和幻影引用,为一个对象设置虚引用关联的唯一目的就是能在这个对象被回收时收到一个系统通知。