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已经死了");
}
}
}