JVM判断对象是否存活

  • Post author:
  • Post category:其他



  • 引用计数算法:

    在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的对象就是不可能再被使用的。

Java邻域,至少在主流的Java虚拟机里面都没有选用引用技术法来管理内存,主要原因是:这个看似简单的算法有很多例外的情况需要考虑,必须要大量配合额外的处理才能保证正确的工作。如单纯的引用很难解决对象之间循环引用的问题。


  • 可达性分析算法:

    这个算法的基本思路就是通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为”引用链“(Reference Chain),如果某个对象到GC Roots间没有任何引用链相连,或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明此对象不可能再被使用的。

在Java技术体系中,固定可以作为GC Roots的对象包括以下几种:

  1. 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等;
  2. 在方法区中类静态属性引用对象,譬如Java类引用类型静态变量;
  3. 在方法区中常量引用对象,譬如字符串常量池(StringTable)里的引用;
  4. 在本地方法栈中JNI(即通常说的Native方法)引用的对象;
  5. Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(NullPointException、OutOfMemoryError)等,还有系统类加载器;
  6. 所有被同步锁(synchronized 关键字)持有的对象;
  7. 反应Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

Java对象的引用

JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(Strongly Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、和虚引用(Phantom Reference)4种,这四种引用强度依次逐渐减弱。


  • 强引用(Strongly Reference):

    指在程序代码之中普遍存在的引用赋值,即类似于”Object obj=new Object()“这种引用关系。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。

  • 软引用(Soft Reference):

    用来描述一些还有用,但非必须的对象。只要被软引用关联着的对象,在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出异常。

  • 弱引用(Weak Reference):

    用来描述那些非必须对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉被弱引用关联的对象。

  • 虚引用(Phantom Reference):

    也较”幽灵引用“和”幻影引用“,是一种最弱的引用关系,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。

·对象生存还是死亡?

即使在可达性分析算法中判断为不可达对象,也并不是”非死不可“的,要真正宣告一个对象死亡,至少要经历两次标记的过程,如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记,随后进行一次筛选,

筛选的条件是此对象是否有必要执行finalize()方法。

假如对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,那么虚拟机将这两种情况都视为”没有必要执行“finalize()方法。

如果这个对象被判断为有必要执行finalize()方法,那么对象将会被放置在一个名为

F-Queue

的队列之中,并在稍后由一条由虚拟机自动建立的、低调度优先级的Finalizer线程去执行它的finalize()方法。


”执行“

是指虚拟机会触发这个方法开始运行,但并不承若会等待它运行结束。这样做的原因是:如果某个对象的finalize()方法执行缓慢,或者更极端地发生死循环,将很有可能导致F-Queue队列中的其他对象永久处于等待,甚至导致整个内存回收子系统的崩溃。

finalize()方法是对象逃脱死亡命运的最后一次机会,稍后收集器将对F-Queue中的对象进行第二次小规模标记,

如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关系即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,

那么第二次标记时它将被移出”即将回收“的集合;如果对象这个时候没有逃脱,那基本上它就真的要被回收了。

任何一个对象的finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法不会再被执行。

回收方法区

  1. 废弃的常量
  2. 不再使用的类型

假如在常量池中存在字符串 “abc”,如果当前没有任何String对象引⽤该字符串常量的话,就说明 常量 “abc” 就是废弃常量,如果这时发⽣内存回收的话⽽且有必要的话,”abc” 就会被系统清理 出常量池。

类需要同时满⾜下⾯

3 个条件

才能算是 “⽆⽤的类” :

  • 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
  • 加载该类的 (类加载器)ClassLoader 已经被回收。
  • 该类对应的 java.lang.Class 对象没有在任何地⽅被引⽤,⽆法在任何地⽅通过反射访问该类 的⽅法。



版权声明:本文为LCB2018原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。