java垃圾回收之如何判断对象已死

垃圾回收主要管理的就是java堆,因为虚拟机栈,本地方法栈,都是线程私有的线程消亡,内存自动回收,并且对象在创建过程时,在栈中需要分配多少内存,是明确知道大小的。如何判断java堆中对象已经失去引用,就显得尤为重要。

1.引用计数算法

为对象添加一个计数器,有引用加1,失去引用,就减1.收集的时候收集,计数器为0的对象。

这种算法,不被java虚拟机作为主流的算法所使用,是因为,java中,对象循环引用,将会造成,计数器永远不为0。从而降低收集效率。具体如下:

class Test{
 public Object init;
}

public static void main(arg 0[]){
    Test t1=new Test();
    Test t2=new Test();
    t1.init=t2;
    t2.inti=t1;
    t1=null;
    t2=null;
    System.gc();
}

2.可达性分析算法

通过一系列称为“GC Roots”对象作为起点,从这些节点,向下搜索,搜索所走过的路径称为引用链,当一个对象到GCRoots没有任何引用链的时候,证明此对象不可达,也就证明对象没有引用,则会被回收。

java可以作为GCroots对象的有:虚拟机栈中本地变量表引用的对象;本地方法栈中native方法引用的对象;方法区中静态属性引用的对象;方法区中常量引用的对象;

在内存空间足够,一些鸡肋对象,可以回收,也可以不回收,但是这类对象已经没有引用。但是还想保留这类对象,所有虚拟机将引用分为四类。这类鸡肋对象,也是一些系统中,放入缓存中的对象。

引用可分为:强引用,软引用,弱引用,虚引用四类。

强引用:就是用直接引用的对象,这类对象永远不会被回收。Object o = new Object();

软引用:这就是那类还有用,但非必须的对象。在报内存溢出异常之前,gc会第二次回收这类对象,会收完如果内存还不够,才会报内存异常。

弱引用:比软引用还要弱,只能活到下次垃圾收集,无论内存是否够,都会被垃圾收集器收集。

虚引用:无法通过需引用来获得对象事例,需引用也不会影响对象的生存周期,设置需引用,就是为了对象在垃圾回收时,收到一个系统通知。

对象的死亡

可达性算法不可达的对象,在经历可达性算法分析后,不能达到GCRoots根节点,将被进行一次标记,要真正的回收对象,至少要被标记两次。如果被第一次标记完成后,会对该对象进行一侧筛选,筛选的条件就是,看对象是否有必要执行,finalize()方法。当对象没覆盖finalize()方法,或者finalize()方法已经被jvm掉用过,这两种情况都视为“没有必要执行”。如果有必要执行finalize()方法,那么该对象将被放到F—Queue队列。jvm将会创建一个低优先级的现场,去执行,触发对象里面的finalize()方法。不会等待对象执行完毕,防止由于某个对象的finalize()方法,发生死锁或者死循环,而导致整个内存回收系统崩溃。

回收方法区

主要回收常量池和无用的类。

回收常量池,常量池中的对象,没有引用,在内存回收时,则被回收。

无用的类:(1)该类的所有实例均被回收。(2)加载该类的ClassLoader已经被回收。(3)该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。类的回收,和对象回收不同,无用的类,仅仅是可以回收,而不是理马上被回收。虚拟机提供了,对应的参数,来设置开启类回收。在大量使用反射,动态代理,CGLib等ByteCode框架、懂赢生成jsp以及OAGI这类频繁自定义ClassLoader的场景下,需要虚拟机具备类卸载功能,保证不发生内存溢出。

你可能感兴趣的:(深入理解JVM)