JVM(2)-对象可用性的判定以及自我拯救

  • Post author:
  • Post category:其他


当一个对象不再被引用时,原本分配给此对象的内存便成为垃圾,在确定该对象“已死”后,才能进行垃圾回收,那么如何判断一个对象是否可用呢?

一、如何判断对象“已死”

1、引用计数法

给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已”死”。

但是引用计数法

无法解决对象的循环引用问题

,因此JVM并没有使用该方法进行垃圾回收

例如:

public class Test {
public Object instance = null;
public static void testGC() {
Test test1 = new Test();
Test test2 = new Test();
test1.instance = test2;
test2.instance = test1;
test1 = null;
test2 = null;
// 强制jvm进行垃圾回收
System.gc();
}
public static void main(String[] args) {
testGC();
}
}
//即使两个对象互相引用,虚拟机仍然进行了回收

2、可达性分析算法

通过一系列称为”GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称之为”引用链”,当一个对象到GC Roots没有任何的引用链相连时(从GC Roots到这个对象不可达)时,证明此对象是不可用的。

在这里插入图片描述

如图,object5,6,7到GC Roots不可达,则该对象不可用

可作为GC Roots的对象:

1.虚拟机栈中引用的对象

2.类静态变量引用的对象

3.常量引用的对象

4.本地方法栈中引用的对象

为什么选用这四种引用作为根节点呢?

作为根节点来判断其余对象是否可达,那么它本身就必须是一组活跃的引用,例如正在被调用的方法的引用,被加载的java类等



JDK1.2之后对于引用的概念做了扩充,分为以下四种



1.强引用:强引用指的是代码中普遍存在的,类似于Object obj = new Object(); 在JVM中只要强引用还在,垃圾回收器永远不会回收此对象实例

2.软引用:软引用用来描述一些有用但不必须的对象。对于仅被软引用指向的对象,在系统将要发生 内存溢出之前,会将所有软引用对象进行垃圾回收。若内存够用,这些对象依然保留。在JDK1.2之后提供的SoftReference来实现软引用

3.弱引用:弱引用强度比软引用差一点,仅被弱引用关联的对象最多只能生存到下一次GC开始之前。当垃圾回收器开始工作时,无论当前内存是否够用,都会回收仅被弱引用关联的对象。JDK1.2之后,使用WeakRerence来实现弱引用

4.虚引用:虚引用也称为幽灵引用或幻影引用,是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间产生影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用的唯一目的就是在这个对象被GC之前,收到一个系统通知。JDK1.2之后,提供PhantomReference来描述虚引用。

二、对象的自我拯救-finalize

protected void finalize() throws Throwable {

在可达性分析算法中不可达的对象并不是非死不可,要宣告一个对象的彻底死亡,需要经历两次标记过程:

若对象在进行可达性分析之后发现到GC Roots不可达,此对象会进行第一次标记并且进行一次筛选过程。筛选的条件是此对象有必要执行finalize()。当对象没有覆盖finalize()方法或该方法已经被JVM调用过,JVM会将此对象彻底宣判死亡

筛选成功(对象覆写了finalize()方法并未被执行),会将此对象放入F-Queue,如果对象在finalize()成功自救(此对象与GC Roots建立联系),则对象会在第二次标记时被移除回收集合,成功存活;若对象在finalize()中仍然与GC Roots不可达,宣告死亡。

三、回收方法区

方法区的回收主要回收两部分:废弃常量和无用的类

如何判断一个类是无用类:

1.该类的所有实例都已经被回收(Java堆中不存在该类的任何实例)

2.加载该类的类加载器已经被回收

3.该类的Class对象没有任何其他地方被引用,也无法通过反射访问该类的所有内容



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