3.1 引用计数算法
给对象中添加一个引用计数器,每当有一个地方引用它时,计数器的数值就加一,当引用失效时,计数器的数值就减一,任何时刻计数器为零的对象就是不可能被使用的。
总结:
引用计数算法实现简单,判定效率也高,但是主流的 Java
虚拟机中没有选用引用计数算法管理内存,其中最主要的原因是它很难解决对象间循环引用的问题。
3.2 可达性分析算法
算法的思路就是通过一系列“GC Roots
” 的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到 GC Roots
没有任何引用链相连(图中 Object5,Object6可回收,从 GC Roots 到这个对象不可达),则证明此对象是不可用的,所以它们将判定为是可回收的对象。
在 Java
语言中,可作为 GC Roots
的对象如下:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 方法区中静态属性引用变量
- 方法区中常量引用对象
- 本地方法区中 JNI (一般来说 Native 方法)引用对象
3.3 四大引用
在 JDK 1.2 之后,Java 对引用的概念进行了扩充,将引用分为强引用(Strong Reference),软引用(Soft Reference),弱引用(Weak Reference),虚引用(Phantom Reference)
-
强引用:程序代码中普遍存在的,“
Object obj = new Object()
” 这类的引用,只要强引用还在,那么垃圾收集器永远都不会回收 -
软引用:描述一些还有用并非必须的对象。对于软引用关联的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出异常。
SoftReference
类来实现。 -
弱引用:别弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉被弱引用关联的对象,
WeakReference
类实现 - 虚引用:被称作幽灵引用或者幻影引用。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也不发通过虚引用来取得一个对象的实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器会收时收到一个系统通知。
3.4 “可达性分析法”算法如何回收
不可达的对象,也并非是“非死不可”,这个时候它们暂时处于"缓刑"状态,要真正宣告一个对象死亡,至少经历两次标记过程:
- 如果对象进行可达性分析之后没有与
GC Roots
相连接的引用链,那么它将会被第一次标记并进行一次筛选,筛选条件是此对象是否有必要执行finalize()
方法。当对象没有覆盖finalize()
方法,或者finalize()
方法已经被虚拟机调试过,虚拟机将这两种情况都视为“没有必要执行”。 - 如果这个对象被判定有必要执行
finalize()
方法,那么这个对象会被放到一个叫FQueue
的队列之中,并自动建立一个,低优先级Finalizer
线程去执行。这里的‘执行’是虚拟机会触发这个方法,但并不会等待他运行结束(发生死循环,执行缓慢,防止堵塞F-Queue
队列),稍后 GC 将对 F-Queue 中的对象进行第二次小规模的标记,如果对象要在 finalize() 中成功拯救自己——只要重新与引用链上任何一个对象建立链接,那在第二次标记时将被移出“即将回收”结合。
网友评论