第三章:JVM断定哪些对象可回收

 

①引用计数算法

原理:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;在任什么时候刻计数器的值为0的对象就是不可能再被使用的,也就是可被回收的对象。web

它有一个致命的缺陷,那就是它没法解决对象之间相互循环引用的的问题,对于循环引用的对象它没法进行回收。算法

public class Object {

public Object instance;

public static void main(String[] args) {

// 1
Object objectA = new Object();
Object objectB = new Object();

// 2
objectA.instance = objectB;
objectB.instance = objectA;

// 3
objectA = null;
objectB = null;

}
}

 

 

程序启动后,objectA和objectB两个对象被建立并在堆中分配内存,这两个对象都相互持有对方的引用,除此以外,这两个对象再无任何其余引用,实际上这两个对象已经不可能再被访问(引用被置空,没法访问),可是它们由于相互引用着对方,致使它们的引用计数器都不为0,因而引用计数算法没法通知GC收集器回收它们。spa

实际上,当第1步执行时,两个对象的引用计数器值都为1;当第2步执行时,两个对象的引用计数器都为2;当第3步执行时,两者都清为空值,引用计数器值都变为1。根据引用计数算法的思想,值不为0的对象被认为是存活的,不会被回收;而事实上这两个对象已经不可能再被访问了,应该被回收。线程

 

 

②可达性分析算法

主流的JVM中,都是经过可达性分析算法来断定对象是否存活的。code

可达性分析算法的基本思想是:经过一系列被称为"GC Roots"的对象做为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots对象没有任何引用链相连,就认为GC Roots到这个对象是不可达的,断定此对象为不可用对象,能够被回收。orm

 

在上图中1234可达的,不会被回收;567它们将会被断定为是可回收的对象。对象

 

在Java中,可做为GC Roots的对象包括下面几种:blog

一、虚拟机栈中引用的对象;接口

二、方法区中类静态属性引用的对象;内存

三、方法区中常量引用的对象;

四、本地方法栈中Native方法引用的对象。

 

③GC Roots对象
在 Java 语言中,可做为 GC Root 的对象包括如下4种:
  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中 JNI(即通常说的 Native 方法)引用的对象

 

★ 虚拟机栈(栈帧中的本地变量表)中引用的对象此时的 s,即为 GC Root,当s置空时,localParameter 对象也断掉了与 GC Root 的引用链,将被回收。

public class StackLocalParameter {

   public StackLocalParameter(String name){}

}

public static void testGC(){

   StackLocalParameter s = new StackLocalParameter("localParameter");

   s = null;

}

★ 方法区中类静态属性引用的对象
s 为 GC Root,s 置为 null,通过 GC 后,s 所指向的 properties 对象因为没法与 GC Root 创建关系被回收。而 m 做为类的静态属性,也属于 GC Root,parameter 对象依然与 GC root 创建着链接,因此此时 parameter 对象并不会被回收。

public class MethodAreaStaicProperties {

   public static MethodAreaStaicProperties m;

   public MethodAreaStaicProperties(String name){}

}

public static void testGC(){

   MethodAreaStaicProperties s = new MethodAreaStaicProperties("properties");

   s.m = new MethodAreaStaicProperties("parameter");

   s = null;

}

★ 方法区中常量引用的对象m 即为方法区中的常量引用,也为 GC Root,s 置为 null 后,final 对象也不会因没有与 GC Root 创建联系而被回收。

public class MethodAreaStaicProperties {

   public static final MethodAreaStaicProperties m = MethodAreaStaicProperties("final");

   public MethodAreaStaicProperties(String name){}

}

public static void testGC(){

   MethodAreaStaicProperties s = new MethodAreaStaicProperties("staticProperties");

   s = null;

}

★  本地方法栈中引用的对象
任何 Native 接口都会使用某种本地方法栈,实现的本地方法接口是使用 C 链接模型的话,那么它的本地方法栈就是 C 栈。当线程调用 Java 方法时,虚拟机会建立一个新的栈帧并压入 Java 栈。然而当它调用的是本地方法时,虚拟机会保持 Java 栈不变,再也不在线程的 Java 栈中压入新的帧,虚拟机只是简单地动态链接并直接调用指定的本地方法。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关文章
相关标签/搜索