JVM之对象是否已死

134 阅读3分钟

一、引用计数法

给对象添加一个引用计数器,每当被引用一次,则计数器加一;引用失效时,计数器值减一;任何时刻计数器为0的对象就是不可能被再使用的。

主流的JVM里面没有选择引用计数法来管理内存,最主要的原因在于它很难理解对象间的相互引用的问题。


二、可达性分析算法

通过一些列称为“GC roots”的对象作为起始点,从这些节点开始向下索引,索引所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时(就是从GC Roots到这个对象是不可达),则证明此对象是不可用的。所以它们会被判定位可回收对象。


在Java语言中,可以作为GC Roots的对象包括下面几种:

  • 虚拟机栈(栈帧中的本地变量表)中引用对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(即Native方法)引用的对象


总之,方法运行时,方法中的引用对象;类的静态变量与类的常量的引用对象,Native方法的引用对象。


在可达性分析算法中,要真正宣布一个对象死亡,至少要经历两次标记过程:

  • 1、对象进行可行性分析时发现没有与GC Roots相连接的引用链,那它将会被第一次标记并进行一次筛选筛选条件此对象是否有必要执行finalize()方法。若对象没有覆盖finalize()方法,或者finalize()方法已经被调用,则该对象被回收;
  • 2、若该对象被判定为又必要执行finalize()方法,那么这个对象将会放置在一个叫F-Queue队列中,并在稍后由虚拟机自动创建的、低优先级的Finalizer线程取执行它。finalize()方法是对象逃脱回收的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()成功拯救自己——重新与引用链中任何一个对象建立关联即可,那么它将不会被回收,移除F-Queue队列;若没有逃逸成功,则基本上它会被回收。


三、判断对象是否存活与“引用”关系

在JDK 1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong Reference)软引用(Soft Reference)弱引用(Weak Reference)虚引用(Phantom Reference)四种,引用强度逐渐减弱

  • 强引用:指在程序代码中普遍存在的,类似“Object obj = new Object()”这类的引用,只要强引用存在,GC收集器永远不会回收被引用的对象。
  • 软引用:指在内存空间足够时,不回收,内存空间不够,则进行回收
  • 弱引用:被弱引用标记的对象,只能存活到下一次GC收集器发生之前。GC收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象,通常对这类对象使用“Reference Queue”进行标记。
  • 虚引用,一个对象是否有虚引用存在完全不会对其生存时间构成印象,也无法通过虚引用来获取一个对象实例。为一个对象设置虚引用的唯一目的就是在这个对象被收集器回收时刻得到一个系统通知。