JVM理论:(二/2)判断对象是否已死

Posted zjxiang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM理论:(二/2)判断对象是否已死相关的知识,希望对你有一定的参考价值。

讲到垃圾回收,首先就要先知道哪些对象是可以回收的。

可达性算法

  这里有必要先了解一下可达性算法,以“GC Roots”的对象作为起始点,若从“GC Roots”到某对象不可达时,此对象会被判定为可回收对象。

  可作为GC Roots的对象包括下面几种:

  1、虚拟机栈(栈帧中的本地变量表)中引用的对象。

  2、方法区中类静态属性引用的对象。

  3、方法区中常量引用的对象。    ?有疑问

  4、本地方法栈中JNI(native方法)引用的对象。

  

  * 作为扩展知识了解一下引用计数法,给对象中添加一个引用计数器,当有一个地方引用它时,计数器值加1,当引用失效时,计数器值减1,计数器为0的对象表示可回收,这种算法存在一个问题,若两个都需要被回收的对象互相引用了,就会导致这两个本该被回收的对象无法被回收。

 

利用finalize()方法逃脱

  即使在可达性分析算法中不可达的对象,也并非马上非死不可,真正判定一个对象死亡至少要经历两次标记过程,判定过程如下:

  1、第一次标记

  如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它会被第一次标记,并根据是否有必要执行finalize()方法进行筛选,若对象没有覆盖finalize()方法或finalize()方法已经被虚拟机调用过,则表示没有必要执行finalize()方法,对象直接被回收。

  2、第二次标记

  如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会被放置在一个名为:F-Queue的队列之中,并在稍后由一条虚拟机自动建立的、低优先级的Finalizer线程去执行,但不保证一定会被执行或会等待它运行结束。

  finalize()方法是对象避免回收的最后一次机会,要成功拯救自己只要重新与引用链上的任何的一个对象建立关联即可,譬如把自己(this)赋值给某个类变量或对象的成员变量。

  * 值得注意的是finalize()方法只能被系统自动调用一次,仅作为了解,一般不使用。

 

四种引用

  判断对象是否存活与“引用”有关,JDK1.2后,Java将引用分为强引用、软引用、弱引用、虚引用4种,引用强度一次减弱。

  将引用分类后,能满足这样的场景:当内存空间足够时,则保留在内存中,如果内存空间在进行垃圾收集后还是非常紧张,则可以抛弃这些对象。  

  1、强引用:

  只要强引用存在,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠回收具有强引用的对象来解决内存不足的问题。

  在程序代码中普遍存在,创建代码即 Object a = new Object()。

  当在一个方法的内部有一个强引用,这个引用保存在栈中,而真正的引用内容(Object)保存在堆中。当这个方法运行完成后就会退出方法栈,则引用内容的引用不存在,这个Object会被回收。

  如果想中断强引用和某个对象之间的关联,a = null;,JVM会在合适的时间回收该对象。

 

  2、软引用:

  在系统将要发生内存溢出异常前,会把这些对象列进回收范围中准备进行第二次回收,如果这次回收还是没有足够的内存才会跑内存溢出异常。即在内存不足时JVM才会回收这些对象。

  软引用用来描述一些有用但并非必需的对象,可用于实现缓存:比如网页缓存、图片缓存等。

  ReferenceQueue softQueue = new ReferenceQueue();

  SoftReference<string> softRef = new SoftReference<string>(new String("软引用"), softQueue);

  通过softRef.get()方法可以取到这个对象,当这个对象被标记为需要回收的对象时,则返回null;

 

  3、弱引用:

  无论内存是否充足,JVM进行垃圾回收时都会被回收(但如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象,软引用也是如此)。

  ReferenceQueue weakQueue = new ReferenceQueue();

  WeakReference<string> weakReference = new WeakReference<string>(new String("弱引用"),weakQueue);    

        

  4、虚引用:

  跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收,也无法通过虚引用来取得一个对象实例。唯一目的是在这个对象被回收时收到一个系统通知。

  ReferenceQueue phantomQueue = new ReferenceQueue();

  PhantomReference<string> phantomReference = new PhantomReference<string>(new String("虚引用"), phantomQueue);

  phantomReference.get();//永远返回null

  phantomReference.isEnQueued();//返回是否从内存中已经删除

  虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。虚引用主要用于检测对象是否已经从内存中删除。    

 

  参考连接:

       https://bbs.csdn.net/topics/390502534

       https://www.cnblogs.com/gudi/p/6403953.html

       https://www.cnblogs.com/dolphin0520/p/3784171.html

       https://www.2cto.com/kf/201609/548593.html


以上是关于JVM理论:(二/2)判断对象是否已死的主要内容,如果未能解决你的问题,请参考以下文章

判断对象是否已死分析总结——JVM系列

JVM的判断对象是否已死和四种垃圾回收算法总结

JVM垃圾回收

JVM学习二:垃圾收集(Garbage Collection,GC)机制

JVM垃圾收集机制

JVM学习-jvm判断对象已死的方法