Java引用

最近在看《深入理解Java虚拟机》,书中讲到判断对象是否存活时讨论了两种算法:一种是引用计数算法,就是给对象添加一个引用计数器,每当有一个地方引用到他时,计数器值就+1,当引用失效时,计数器就-1,任何时刻计数器为0的对象就是不可能在被使用的对象;另一种是可达性分析算法 ,通过一系列称为“GC Roots”的对象作为起点,从他开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连接时则证明对象是不可用的。
但是我们发现无论是引用计数算法还是可达性分析算法都与“引用”有关,那就让我们对引用作进一步的了解。
首先什么是引用?
举个简单例子:ABC abc = new ABC(); abc就是引用变量,它指向了一个对象ABC,也可以说它引用了一个ABC对象,我们可以通过abc来操作对象ABC。
此时abc存储的就是所引用对象的地址值。
如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就成这块内存代表着一个引用。(这种定义过于存粹)我们希望能描述这样一类对象:当内存空间还足够时,则能保存在内存中;如果内存空间在进行垃圾回收后还是很紧张,则可以抛弃这块内存。所以在jdk1.2之后对引用的概念又进行了扩充,将引用分为强、软、弱、虚四种引用。
Java中的四种引用:强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)、虚引用(PhantomReference)。
①强引用:就是指在程序代码中普遍存在的,类似“Object obj = new Object()”这类的引用只要强引用还在,当内存不足时,JVM即使抛出OOM异常使程序异常终止,不会去回收强引用。

②软引用:如果一个对象只具有软引用,内存足够,垃圾回收器就不回收,如果内存不足,则回收这些对象的内存。也就是只要垃圾回收器没有回收它,该对象就可以被程序使用。

public class TestSoftReference {
    public static void main(String[] args) {
        Object object = new Object();
        SoftReference<Object> rf = new SoftReference<Object>(object);//
        System.out.println(rf.get());
        System.gc();
        object=null;
        System.out.println(rf.get());
    }
}

运行结果为:java.lang.Object@7852e922 java.lang.Object@7852e922
说明当内存充足时,一个对象只具有软引用也不会被JVM回收。

③弱引用:与软引用类似,区别在于只具有弱引用的对象生命周期更短。在垃圾回收器线程扫描范围内,一旦发现只具有弱引用的对象,不管当前内存空间是否足够都会对其进行回收。不过,由于垃圾回收器是一个优先级别很低的一个线程,因此不会立刻发现那些只具有弱引用的对象。

public class TestWeakReference {
      public static void main(String[] args) {
          Object obj = new Object();
          WeakReference<Object> wr = new WeakReference(obj);
          System.out.println(wr.get());
          obj = null;
          System.gc();
          System.out.println(wr.get());//null,这是因为WeakReference被回收
      }
}

运行结果:java.lang.Object@7852e922 null
说明在指向obj = null语句之前,Object对象有两条引用路径,其中一条为obj强引用类型,另一条为wr弱引用类型。此时无论如何也不会进行垃圾回收。当执行了obj = null.Object对象就只具有弱引用,并且我们进行了显示的垃圾回收。因此此具有弱引用的对象就被GC给回收了。

④虚引用:顾名思义就是“形同虚设”,也就是说他不会影响对象的生命周期。他的作用为:跟踪垃圾回收器手机对象这一活动的情况。
当GC一旦发现了虚引用对象,则会将其对象插入RefeenceQueue队列,此时该对象还未被垃圾回收器回收,而是要等到ReferenceQueue被真正处理后才会收。

public class TestPhantomReference {
        private static ReferenceQueue<Object> rq = new ReferenceQueue<Object>();
        public static void main(String[] args){

            Object obj = new Object();
            PhantomReference<Object> pr = new PhantomReference<Object>(obj, rq);
            System.out.println(pr.get());
            obj = null;
            System.gc();
            System.out.println(pr.get());
            Reference<Object> r = (Reference<Object>)rq.poll();
            if(r!=null){
                System.out.println("回收");
            }
        }
    }

运行结果:null null 回收。
说明
1)在上面的代码中,如果obj被置为null,当GC发现虚引用,GC会将把PhantomReference对象pr加入到队列ReferenceQueue中,注意此时pr所指向的对象并没有被回收,在我 们显示的调用了rq.poll()返回Reference对象之后,当GC第二次发现虚引用,而此时JVM将虚引用pr插入到队列rq会插入失败,此时GC才会对虚引用对象进行回收。
2)程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否否将要被垃圾回收,如果程序发现某个虚引用已经加入到引用队列,那么就可以再引用对象的内存被回收之前采取必要的行动。

PhantomReference的get方法无论在上面情况下都是返回null。这个在PhantomReference源码中可以看到
PhantomReference的get方法无论在上面情况下都是返回null。这个在PhantomReference源码中可以看到

参考文献:http://blog.csdn.net/u010412719/article/details/52035792

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值