Java垃圾回收之根搜索算法

1.根搜索算法

Java使用根搜索算法回收垃圾,该算法的基本原理:定义一系列名为GC Roots的对象作为起点,从起点向下搜索,搜索所走过的路径称为引用链。

当一个对象到GC Roots没有任何引用链相连,则说明该对象不可用,这时Java虚拟机可以对这些对象进行回收。

Java虚拟机将以下对象定义为 GC Roots :

  • Java虚拟机栈中引用的对象:比如方法里面定义这种局部变量 User user= new User();
  • 静态属性引用的对象:比如 private static User user = new User();
  • 常量引用的对象:比如 private static final  User user = new User();
  • 本地方法栈中引用的对象

2.引用的定义

2.1 强引用Strong Reference

Object obj = new Object();


这里obj 就是引用,new Object() 对象实例存储在堆内存,obj引用的是对象实例的内存地址。

如果执行 obj = null, 那么看起来 new Object() 这个对象实例没有被任何引用持有。

由此看来:引用要么存在,要么不存在。如果没有任何引用持有对象,那么对象可以被JVM回收了。

但有一些缓存系统,希望这些对象不要那么快被回收,因此在JDK1.2之后又定义了另外3种引用类型。

 

2.2 软引用 Soft Reference

用来描述可用,但不是必须存活的对象。

在内存溢出之前,虚拟机尝试对这些对象进行回收。如果回收之后内存还是不够才会出现内存溢出情况。

 

2.3 弱引用 Weak Reference

也是描述非必须的对象,但它的引用比软引用还要弱一些。

被弱引用关联的对象只能生存到下一次垃圾回收发生之前。

只要垃圾回收机制在工作,无论内存是否足够,都会回收掉这部分对象。

 

2.4 虚引用 Phantom Reference

最弱的引用关系,一个对象是否被虚引用关联,完全不对其生存周期构成影响。

也不能通过一个虚引用获取到一个对象实例!

 

3. 根搜索算法之圾回收执行机制

前面介绍了根搜索算法和引用的定义,我们知道【不可达的对象】,就是JVM回收的重点对象。

但即便引用链不可达,也并不意味着该对象一定会被回收,因为回收要经历两次标记过程!

第一次标记:对象进行根搜索之后,如果发现没有与GC Roots 相连接的引用链,就会被第一次标记并进行筛选

所谓筛选,就是检查此对象是否有必要执行finalize方法,如果对象定义了该方法并且没有执行过。

那么该对象就会被放入到一个队列F-Queue,随后会有一个低优先级的线程去执行这个队列里面对象的finalize方法

第二次标记:JVM 将对F-Queue队列里面的对象进行第二次标记。

如果对象不想被回收,那么就得在finalize方法里面拯救自己,否则,这些对象就真的会被回收

 

看以下代码示例就明白垃圾回收的基本过程

package reference.test;

/**
 * 
 * @author yli
 *
 */
public class GCRootsTest {

	private static GCRootsTest obj;

	protected void finalize() throws Throwable {
		super.finalize();
		System.out.println("finalize方法被执行!");
		obj = this;
	}

	public static void main(String[] args) throws InterruptedException {
		obj = new GCRootsTest();

		obj = null;
		System.gc();

		Thread.sleep(500);
		if (null != obj) {
			System.out.println("1-obj还存活着!");
		} else {
			System.out.println("1-obj已经死了");
		}

		obj = null;
		System.gc();

		Thread.sleep(500);
		if (null != obj) {
			System.out.println("2-obj还存活着!");
		} else {
			System.out.println("2-obj已经死了");
		}
	}
}


 

 

 

 

你可能感兴趣的:(Java)