美文网首页
Java Reference详解

Java Reference详解

作者: zivxia | 来源:发表于2017-12-13 15:17 被阅读36次

    本文参考了:
    http://blog.csdn.net/androidstar_cn/article/details/54710652
    http://blog.csdn.net/qq_32347977/article/details/51655521

    Reference是java中的引用类,它用来给普通对像进行包装,从而在JVM在GC时,按照引用类型的不同,在回收时采用不同的逻辑。先来看下这个类的继承体系:


    image.png

    在进行对这些子类进行分析解释之前,我们先来看几个概念:

    对象的生命周期
    image.png

    1.创建阶段(Created)
    在创建阶段系统通过下面的几个步骤来完成对象的创建过程

    • 为对象分配存储空间
    • 开始构造对象
    • 从超类到子类对static成员进行初始化
    • 超类成员变量按顺序初始化,递归条用超类的构造方法
    • 子类成员变量按顺序初始化,子类构造方法调用
      一旦对象被创建,并被分派给某些变量赋值,这个对象的状态就切换到了应用阶段。下面通过具体示例看看:
    public class GrandParent {
    
        public GrandParent(){
            super();
            System.out.println("GrandParent 构造函数");
        }
    
        {
            System.out.println("GrandParent 成员代码块");
        }
    
        static {
            System.out.println("GrandParent 静态代码块");
        }
    }
    
    public class Parent extends GrandParent {
    
    
        public Parent() {
            super();
            System.out.println("Parent 构造函数");
        }
    
        {
            System.out.println("Parent 成员代码块");
        }
    
        static {
            System.out.println("Parent 静态代码块");
        }
    
    
    }
    
    public class Child extends Parent {
    
    
        public Child() {
            super();
            System.out.println("Child 构造函数");
        }
    
        {
            System.out.println("Child 成员代码块");
        }
    
        static {
            System.out.println("Child 静态代码块");
        }
    
    
    }
    

    child为子类,parent为child的超类,GrandParent为超类的超类,当我们执行

    Child child = new Child();
    

    执行顺序为:


    image.png

    当我们执行

    Parent parent = new Parent();
    

    执行顺序为:


    image.png

    从而证明了一个对象创建阶段的执行顺序。
    2.应用阶段(In Use)
    对象至少被一个强引用持有着。即上述例子中的child持有new Child()的强引用。
    3.不可见阶段(Invisible)

    当一个对象处于不可见阶段时,说明程序本身不再持有该对象的任何强引用,虽然这些引用是存在着的。简单说就是程序的执行已经超出了该对象的作用域了。举例来说: image.png
    则在此时称之为count处于不可视阶段。当然这种情况编译器在编译的过程中会直接报错了。
    4.不可达阶段(Unreachable)

    对象处于不可达阶段是指该对象不再被任何强引用所持有。与"不可见阶段"相比,"不可达阶段"是指程序不再持有该对象的任何强引用,这种情况下,该对象仍可能被JVM等系统下的某些已装载的静态变量或线程或JNI等强引用持有着,这些特殊的强引用被称为"GC root"。存在着这些GC root会导致对象的内存泄露情况,无法被回收。
    5.收集阶段(Collected)
    当垃圾回收器发现该对象已经处于"不可达阶段"并且垃圾回收起已经对该对象的内存空间重新分配做好准备时,则对象进入了"收集阶段"。如果该对象已经重写了finalize()方法,则会去执行该方法的终端操作。这里要注意尽量不要重载finalize()方法,原因有两点:

    • 会影响JVM的对象分配于回收速度
      在分配该对象时,JVM需要在垃圾回收器上注册该对象,以便在回收时能够执行该重载方法;在该方法执行时需要消耗CPU时间且在执行完该方法后才会重新执行回收操作,即至少需要垃圾回收器对该对象执行两次GC。
    • 可能造成该对象的再次"复活"
      在finalize()方法中,如果有其它的强引用再次持有该对象。则会导致对象的状态由" 收集阶段"又重新变为"应用阶段"。这个已经破坏了Java对象的生命周期进程,且复活的对象不利于后续代码管理。
    • 终结阶段(Finished)
      当对象执行完finalize()方法后处于不可达状态时,则该对象进入终结状态。在该阶段是等待垃圾回收器对该对象空间进行回收。
    • 对象空间重分配阶段(De-allocated)
      垃圾回收器对该对象的所占用的内存空间进行回收或者再分配,则该对象测底消失了,称之为"对象空重新分配阶段"
    对象可达性判断

    jvm 发生gc时,判断一个对象是否存在引用,都是从根结合引用开始去标识,往往到达一个对象的引用路径会很多,如下图:


    image.png

    那么垃圾回收时会依据两个原则来判断对象的可达性:
    单一路径中,以最弱的引用为准
    多路径中,以最强的引用为准
    例如Obj4的引用,存在:1>6、2>5、3>4,那么从根对象到Obj4的最强引用为2>5,因为它们都是强引用。如果仅仅村子一个路径对Obj4有引用时,比如Obj4有引用时,比如现在只剩下1>6,那么根对象到Obj4的引用以最弱的为准。是软引用。Obj4就是softly-reachable对象。

    强引用(StrongReference)

    强引用就是我们平时创建对象,创建数组时的引用。强引用在任何时候都不会被GC回收掉。例如

    Parent parent = new Parent();
    
    软引用(SoftReference)

    软引用是在系统发生OOM之前才被JVM回收掉。软引用常被用来对于内存敏感的缓存。

    弱引用(WeakReference)

    一旦JVM执行GC,弱引用就会被回收掉。

    (虚引用)PhantomReference

    虚引用主要作为其指向referent被回收时的一种通知机制。

    总结

    通过对SoftReference,WeakReference,PhantomReference,可以看出JDK提供这些类型的reference 主要是用来和GC交互的,根据reference的不同,让JVM采用不同策略来进行对对象的回收(reclaim)。softly-reachable的referent在保证在OutOfMemoryError之前回收对象,weakly-reachable的referent在发生GC时就会被回收,。

    相关文章

      网友评论

          本文标题:Java Reference详解

          本文链接:https://www.haomeiwen.com/subject/adpaixtx.html