精华内容
参与话题
问答
  • 对@Reference 、@Resource和@Autowired的简单理解

    万次阅读 多人点赞 2018-11-20 00:26:33
    主要谈一下对这三个注解的简单理解: @Reference 、@Resource和@Autowired

    主要谈一下对这三个注解的简单理解:

    1.@Autowired

    org.springframework.beans.factory.annotation.Autowired

    SpringBoot项目中常用。简单来说就是引入由Spring容器管理的bean。

    2.@Resource

    javax.annotation.Resource

    作用相当于@Autowired,只不过@Autowired是byType自动注入,而@Resource默认byName自动注入。

    3.@Reference

    @Reference是dubbo的注解,也是注入,他一般注入的是分布式的远程服务的对象,需要dubbo配置使用。

     

    简单来说他们的区别:

    @Reference注入的是分布式中的远程服务对象,@Resource和@Autowired注入的是本地spring容器中的对象。

    展开全文
  • Reference详解

    2018-04-23 17:19:47
    1. 概述图片引用自...当Reference对象被GC处理过,说明这个Reference所指向的对象已经被回收过了,那么这个Reference对象也应该做相应的处理;如果该Referenc...

    1.   概述

    图片引用自https://blog.csdn.net/u011801189/article/details/52723868

    根据Reference这个类里面的注释,整个Reference的继承体系跟GC是紧密联系在一起的。当Reference对象被GC处理过,说明这个Reference所指向的对象已经被回收过了,那么这个Reference对象也应该做相应的处理;如果该Reference对象注册了ReferenceQueue,那么它就会被丢到相应的ReferenceQueue中做回收处理。

    从上图注意到,当Reference对象在Reference.pending队列中时,它们是用discovered 这个成员变量来完成队列的连接的;

    这个Reference对象是active的状态,说明这个Reference所指向的对象还没有成为垃圾,还没有被GC过。这个Reference对象还没有进入Reference的世界,它还在GC的监控下呢;当被垃圾回收后,也就是进入Reference的世界后,这个discovered域被复用作链表的连接,此时并不适用next指针,只是把next指向this

    Reference对象真正被放入它所注册的ReferenceQueue里时,next指针才被使用,用来连接队列;此时discovered域被置为null

    2.   Reference适用场景

    . 软引用,一般使用于一些内存敏感性应用,做cache使用。被软引用的对象,在JVM抛出OutOfMemoryError之前,将会被回收掉。它的这个特性使得它做为进程内部的cache最为合适。 

    弱引用,一般用于保存一些跟对象生命周期相同的一些信息,一旦这些对象被垃圾回收,我们就可以对这些对象进行回收。这个是怎么做到的呢?基本上还是由于Reference所提供的功能有关。去看Reference的构造函数你会发现,它会要求传入一个ReferenceQueue,而这个Queue就是为了提供一种机制,这种机制允许程序员在对象被垃圾回收之前被通知到,而做出一些业务逻辑。而这种机制则弥补了JVMfinalizer机制的不足。因为JVMfinalizer机制并不保证finalizer一定会被调用到,这样当我们希望一个对象生命周期结束后它的相关资源也被释放的逻辑就不能够被保证。而且据说(为证实),finalizer是通过JNI实现,通过JVM调用开销也比较大。而JVM通过提供这种Reference机制,从而为程序员提供了处理资源回收的另外一种方法。 

    虚引用,也是可以提供这种对象被垃圾回收时的通知机制。只不过跟上面两个的区别是,PhantomReferenceget方法被实现了一直返回null。这就意味着,当你通过ReferenceQueue拿到PhantomReference的通知时,你是不能再对它做出一个强引用的,你只能更具需要做出自己的cleanup的逻辑。这也说明了PhantomReferencepre-mortem的,也就是说实在真正finalize之前的。如果通过get方法可以获得对象本身,而后又对其建立一个强引用,则在后面的垃圾回收处理时,就会出错。所以干脆这里不让程序员获得对象的引用。而SoftReferenceWeakReference应该就是在JVMfinalize机制之后的。

     

    今天吃饭的时候想到一个问题,就是对于PhantomReference,它的get方法是返回的null的,如果是这样,我通过ReferenceQueue的方式即使能拿到这个PhantomReference,也还是不能对这个对象做实质的资源回收啊。那到底要怎么做才能回收与它的referent想关联的资源呢?

    publicclassLargeObjectFinalizerextendsPhantomReference<Object> {

     

        publicLargeObjectFinalizer(

          Object referent, ReferenceQueue<? super Object> q) {

            super(referent, q);

        }

     

        publicvoidfinalizeResources() {

            // free resources

            System.out.println("clearing ...");

        }

    }

    然后,在利用这个LargeObjectFinalizer关联到我们的referent

    ReferenceQueue<Object>referenceQueue = new ReferenceQueue<>();

    List<LargeObjectFinalizer>references = new ArrayList<>();

    List<Object>largeObjects = new ArrayList<>();

     

    for (int i = 0; i < 10; ++i) {

        Object largeObject = new Object();

        largeObjects.add(largeObject);

        references.add(new LargeObjectFinalizer(largeObject,referenceQueue));

    }

     

    largeObjects= null;

    System.gc();

     

    Reference<?>referenceFromQueue;

    for(PhantomReference<Object> reference : references) {

        System.out.println(reference.isEnqueued());

    }

     

    while((referenceFromQueue = referenceQueue.poll()) != null) {

        ((LargeObjectFinalizer)referenceFromQueue).finalizeResources();

        referenceFromQueue.clear();

    }

    上面的这个例子很简单,但是足够可以说明问题,当垃圾回收工作时,会把我们的LargeObjectFinalizer放到我们提供的referenceQueue上,然后,我们从它上面取下我们的LargeObjectFinalizer,调用资源回收方法finalizeResources

    我觉得这个算是使用PhantomReference做垃圾回收的一个典型例子了。我们并不是直接使用PhantomReference,而是通过扩展它,将我们要关注的对象,比如这里的Object,以及跟该对象相关联的一些资源,关联到我们的LargeObjectFinalizer中,当然这是需要修改它的构造函数,或者通过其它的一些方式关联到这个LargeObjectFinalizer里面的。只有这样,我们才能通过这个ReferenceQueue的机制,达到垃圾回收的目的。

     

    3.     StrongReference、SoftReference,WeakReference、PhantomReference

     强引用  >  软引用  >  弱引用  >  虚引用

    强引用(StrongReference
        强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。

    软引用(SoftReference

        如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。

        软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

    弱引用(WeakReference

        弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

        弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

    虚引用(PhantomReference

        “虚引用顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

        虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

     

    由于引用和内存回收关系紧密。下面,先通过实例对内存回收有个认识;然后,进一步通过引用实例加深对引用的了解。

     

     


    展开全文
  • 我们知道java语言提供了4种引用类型:强引用、软引用(SoftReference)、弱引用(WeakReference)和幽灵引用(PhantomReference),与引用密切相关的,还有一个引用队列ReferenceQueue。引用和引用队列的关系,对于...

    我们知道java语言提供了4种引用类型:强引用、软引用(SoftReference)、弱引用(WeakReference)和幽灵引用(PhantomReference),与引用密切相关的,还有一个引用队列ReferenceQueue。引用和引用队列的关系,对于垃圾回收来说非常重要,学习垃圾回收机制,必须要先了解引用和引用队列的使用方法。本文主要参考网上的一些理论,同时配合自己的一些测试代码,更好的理解这些概念。这篇博客也解决了 System.gc()和-XX:+DisableExplicitGC启动参数,以及DirectByteBuffer的内存释放  中遗留的幽灵引用的问题。


    1、强引用

         强引用不会被GC回收,并且在java.lang.ref里也没有实际的对应类型,平时工作接触的最多的就是强引用。
      Object obj = new Object();这里的obj引用便是一个强引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。


    2、软引用

    如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只 要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

    /**
     * 只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收
     * 
     * <pre>
     * 无论是否发送GC,执行结果都是:
     * java.lang.Object@f9f9d8
     * null
     * java.lang.Object@f9f9d8
     * null
     * </pre>
     * 
     * 可以看到:只有发送了GC,将对于从内存中释放的时候,JVM才会将reference假如引用队列
     */
    public static void soft() throws Exception
    {
    	Object obj = new Object();
    	ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
    	SoftReference<Object> softRef = new SoftReference<Object>(obj, refQueue);
    	System.out.println(softRef.get()); // java.lang.Object@f9f9d8
    	System.out.println(refQueue.poll());// null
    
    	// 清除强引用,触发GC
    	obj = null;
    	System.gc();
    
    	System.out.println(softRef.get());
    
    	Thread.sleep(200);
    	System.out.println(refQueue.poll());
    }
    这里有几点需要说明:

    1、System.gc()告诉JVM这是一个执行GC的好时机,但具体执不执行由JVM决定(事实上这段代码一般都会执行GC)

    2、Thread.sleep(200); 这是因为从对象被回收到JVM将引用加入refQueue队列,需要一定的时间。而且poll并不是一个阻塞方法,如果没有数据会返回null,所以我们选择等待一段时间。


    3、弱引用

    如果一个对象只具有弱引用,那就类似于可有可物的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。  弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回 收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。 

    /**
     * 弱引用: 当发生GC的时候,Weak引用对象总是会内回收回收。因此Weak引用对象会更容易、更快被GC回收。
     * Weak引用对象常常用于Map数据结构中,引用占用内存空间较大的对象
     * 
     * <pre>
     * 如果不发生垃圾回收: 
     * java.lang.Object@f9f9d8 
     * null 
     * java.lang.Object@f9f9d8
     * null
     * 
     * 如果发生垃圾回收:
     * java.lang.Object@f9f9d8
     * null
     * null
     * java.lang.ref.WeakReference@422ede
     * 
     * <pre>
     */
    public static void weak() throws Exception
    {
    	Object obj = new Object();
    	ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
    	WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue);
    	System.out.println(weakRef.get()); // java.lang.Object@f9f9d8
    	System.out.println(refQueue.poll());// null
    
    	// 清除强引用,触发GC
    	obj = null;
    	System.gc();
    
    	System.out.println(weakRef.get());
    
    	// 这里特别注意:poll是非阻塞的,remove是阻塞的.
    	// JVM将弱引用放入引用队列需要一定的时间,所以这里先睡眠一会儿
    	// System.out.println(refQueue.poll());// 这里有可能是null
    
    	Thread.sleep(200);
    	System.out.println(refQueue.poll());
    	// System.out.println(refQueue.poll());//这里一定是null,因为已经从队列中移除
    
    	// System.out.println(refQueue.remove());
    }
    这里需要注意下:

    1、remove这是一个阻塞方法,类似于J.U.C并发包下的阻塞队列,如果没有队列没有数据,那么当前线程一直等待。

    2、如果队列有数据,那么remove和pool都会将第一个元素出队。

    4、幽灵引用(虚引用)

    虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。由于Object.finalize()方法的不安全性、低效性,常常使用虚引用完成对象回收前的资源释放工作。参考我的另一篇博客:解释为什么finalize是不安全的,不建议使用

    /**
     * 当GC一但发现了虚引用对象,将会将PhantomReference对象插入ReferenceQueue队列.
     * 而此时PhantomReference所指向的对象并没有被GC回收,而是要等到ReferenceQueue被你真正的处理后才会被回收.
     * 
     * <pre>
     * 不发生GC执行结果是:
     * null
     * null
     * null
     * null
     * 
     * 发生GC执行结果是:
     * null
     * null
     * null
     * java.lang.ref.PhantomReference@87816d
     * </pre>
     * 
     * 虚引用在实现一个对象被回收之前必须做清理操作是很有用的,比finalize()方法更灵活
     */
    public static void phantom() throws Exception
    {
    	Object obj = new Object();
    	ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
    	PhantomReference<Object> phantom = new PhantomReference<Object>(obj,
    			refQueue);
    	System.out.println(phantom.get()); // java.lang.Object@f9f9d8
    	System.out.println(refQueue.poll());// null
    
    	obj = null;
    	System.gc();
    
    	// 调用phanRef.get()不管在什么情况下会一直返回null
    	System.out.println(phantom.get());
    
    	// 当GC发现了虚引用,GC会将phanRef插入进我们之前创建时传入的refQueue队列
    	// 注意,此时phanRef所引用的obj对象,并没有被GC回收,在我们显式地调用refQueue.poll返回phanRef之后
    	// 当GC第二次发现虚引用,而此时JVM将phanRef插入到refQueue会插入失败,此时GC才会对obj进行回收
    	Thread.sleep(200);
    	System.out.println(refQueue.poll());
    }
    这里特别需要注意:当JVM将虚引用插入到引用队列的时候,虚引用执行的对象内存还是存在的。但是PhantomReference并没有暴露API返回对象。如NIO直接内存的自动回收,就使用到了sun.misc.Cleaner

    public class Cleaner extends PhantomReference
    {
    }

    JDK底层源码查询网站:http://www.docjar.com/html/api/sun/misc/Cleaner.java.html


    5、小结

    引用和引用队列提供了一种通知机制,允许我们知道对象已经被销毁或者即将被销毁。GC要回收一个对象的时候,如果发现该对象有软、弱、虚引用的时候,会将这些引用加入到注册的引用队列中。软引用和弱引用差别不大,JVM都是先把SoftReference和WeakReference中的referent字段值设置成null,之后加入到引用队列;而虚引用则不同,如果某个堆中的对象,只有虚引用,那么JVM会将PhantomReference加入到引用队列中,JVM不会自动将referent字段值设置成null。


    参考资料:

    Java:对象的强、软、弱和虚引用    http://zhangjunhd.blog.51cto.com/113473/53092/

    Java 中的 Reference              http://www.cnblogs.com/newcj/archive/2011/05/15/2046882.html



    展开全文
  • Java基本功之Reference详解

    万次阅读 2017-06-23 13:43:44
    有这样一种说法,如今争锋于IT战场的两大势力,MS一族偏重于底层实现,Java一族偏重于系统架构。说法根据无从考证,但从两大势力各自的社区力量和图书市场已有... Reference Java世界泰山北斗级大作《Thinking In J

    有这样一种说法,如今争锋于IT战场的两大势力,MS一族偏重于底层实现,Java一族偏重于系统架构。说法根据无从考证,但从两大势力各自的社区力量和图书市场已有佳作不难看出,此说法不虚。于是,事情的另一面让人忽略了。偏巧,我是一个喜欢探究底层实现的Java程序员,虽然我的喜好并非纯正咖啡,剑走偏锋却别是一番风味。
      
      Reference Java世界泰山北斗级大作《Thinking In Java》切入Java就提出“Everything is Object”。在Java这个充满Object的世界中,reference是一切谜题的根源,所有的故事都是从这里开始的。
      
      Reference是什么?
      
      如果你和我一样在进入Java世界之前曾经浪迹于C/C++世界,就一定不会对指针陌生。谈到指针,往日种种不堪回首的经历一下子涌上心头,这里不是抱怨的地方,让我们暂时忘记指针的痛苦,回忆一下最初接触指针的甜蜜吧!
      
      还记得你看过的教科书中,如何讲解指针吗?留在我印象中的一种说法是,指针就是地址,如同门牌号码一样,有了地址,你可以轻而易举找到一个人家,而不必费尽心力的大海捞针。C++登上历史舞台,reference也随之而来,容我问个小问题,指针和reference区别何在?我的答案来自于在C++世界享誉盛名的《More Effective C++》。
      
      没有null reference,reference必须有初值。
      
      使用reference要比使用指针效率高。因为reference不需要测试其有效性。指针可以重新赋值,而reference总是指向它最初获得的对象。
      
      设计选择:
      
      当你指向你需要指向的某个东西,而且绝不会改指向其它东西,或是当你实作一个运算符而其语法需要无法有指针达成,你就应该选择reference。其它任何时候,请采用指针。
      
      这和Java有什么关系?
      
      初学Java,鉴于reference的名称,我毫不犹豫的将它和C++中的reference等同起来。不过,我错了。在Java中,reference 可以随心所欲的赋值置空,对比一下上面列出的差异,就不难发现,Java的reference如果要与C/C++对应,它不过是一个穿着 reference外衣的指针而已。于是,所有关于C中关于指针的理解方式,可以照搬到Java中,简而言之,reference就是一个地址。我们可以把它想象成一个把手,抓住它,就抓住了我们想要操纵的数据。如同掌握C的关键在于掌握指针,探索Java的钥匙就是reference。
      
      一段小程序
      
      我知道,太多的文字总是令人犯困,那就来段代码吧!
      
      public class ReferenceTricks
      {
      public static void main(String[] args)
      {
      ReferenceTricks r = new ReferenceTricks();
      // reset integer
      r.i = 0;
      System.out.println
      ("Before changeInteger:" + r.i);
      changeInteger(r);
      System.out.println
      ("After changeInteger:" + r.i);
      
      // just for format
      System.out.println();
      
      // reset integer
      r.i = 0;
      System.out.println
      ("Before changeReference:" + r.i);
      changeReference(r);
      System.out.println
      ("After changeReference:" + r.i);
      }
      
      private static void
      changeReference(ReferenceTricks r)
      {
      r = new ReferenceTricks();
      r.i = 5;
      System.out.println
      ("In changeReference: " + r.i);
      }
      
      private static void
      changeInteger(ReferenceTricks r)
      {
      r.i = 5;
      System.out.println
      ("In changeInteger:" + r.i);
      }
      
      public int i;
      }
      
      我知道,把一个字段设成public是一种不好的编码习惯,这里只是为了说明问题。如果你有兴趣自己运行一下这个程序。你已经运行过了吗?结果如何?是否如你预期?下面是我在自己的机器上运行的结果:
      
      Before changeInteger:0
      In changeInteger:5
      After changeInteger:5
      
      Before changeReference:0
      In changeReference: 5
      After changeReference:0
      
      这里,我们关注的是两个change,changeReference和changeInteger。从输出的内容中,我们可以看出,两个方法在调用前和调用中完全一样,差异出现在调用后的结果。
      
      糊涂的讲解
      
      先让我们来分析一下changeInteger的行为。
      
      前面说过了,Java中的reference就是一个地址,它指向了一个内存空间,这个空间存放着一个对象的相关信息。这里我们暂时不去关心这个内存具体如何排布,只要知道,通过地址,我们可以找到r这个对象的i字段,然后我们给它赋成5。
      
      既然这个字段的内容得到了修改,从函数中返回之后,它自然就是改动后的结果了,所以调用之后,r对象的i字段依然是5。下图展示了changeInteger调用前后内存变化。
      
      让我们把目光转向changeReference。从代码上,我们可以看出,同changeInteger之间的差别仅仅在于多了这么一句:
      
      r = new ReferenceTricks();
      
      这条语句的作用是分配一块新的内存,然后将r指向它。执行完这条语句,r就不再是原来的r,但它依然是一个ReferenceTricks的对象,所以我们依然可以对这个r的i字段赋值。到此为止,一切都是那么自然。
      
      顺着这个思路继续下去的话,执行完changeReference,输出的r的i字段,那么应该是应该是新内存中的i,所以应该是5。至于那块被我们抛弃的内存,Java的GC功能自然会替我们善后的。
      
      事与愿违。
      
      实际的结果我们已经看到了,输出的是0。肯定哪个地方错了,究竟是哪个地方呢?
      
      参数传递的秘密
      
      知道方法参数如何传递吗?
      
      记得刚开始学编程那会儿,老师教导,所谓参数,有形式参数和实际参数之分,参数列表中写的那些东西都叫形式参数,在实际调用的时候,它们会被实际参数所替代。
      
      编译程序不可能知道每次调用的实际参数都是什么,于是写编译器的高手就出个办法,让实际参数按照一定顺序放到一个大家都可以找得到的地方,以此作为方法调用的一种约定。所谓“没有规矩,不成方圆”,有了这个规矩,大家协作起来就容易多了。这个公共数据区,现在编译器的选择通常是“栈”,而所谓的顺序就是形式参数声明的顺序。
      
      显然,程序运行的过程中,作为实际参数的变量可能遍布于内存的各个位置,而并不一定要老老实实的呆在栈里。为了守“规矩”,程序只好将变量复制一份到栈中,也就是通常所说的将参数压入栈中。
      
      我刚才说什么来着?将变量复制一份到栈中,没错,“复制”!
      
      这就是所谓的值传递。
      
      C语言的旷世经典《The C Programming Language》开篇的第一章中,谈到实际参数时说,“在C中,所有函数的实际参数都是传‘值’的”。
      
      马上会有人站出来,“错了,还有传地址,比如以指针传递就是传地址”。不错,传指针就是传地址。在把指针视为地址的时候,是否考虑过这样一个问题,它也是一个变量。前面的讨论中说过了,参数传递必须要把参数压入栈中,作为地址的指针也不例外。所以,必须把这个指针也复制一份。函数中对于指针操作实际上是对于这个指针副本的操作。
      
      Java的reference等于C的指针。所以,在Java的方法调用中,reference也要复制一份压入堆栈。在方法中对reference的操作就是对这个reference副本的操作。
      
      谜底揭晓
      
      好,让我们回到最初的问题上。在changeReference中对于reference的赋值实际上是对这个reference的副本进行赋值,而对于reference的本尊没有产生丝毫的影响。
      
      回到调用点,本尊醒来,它并不知道自己睡去的这段时间内发生过什么,所以只好当作什么都没发生过一般。就这样,副本消失了,在方法中对它的修改也就烟消云散了。
      
      也许你会问出这样的问题,“听了你的解释,我反而对changeInteger感到迷惑了,既然是对于副本的操作,为什么changeInteger可以运作正常?”这是很有趣的现象。
      
      好,那我就用前面的说法解释一下changeInteger的运作。所谓复制,其结果必然是副本完全等同于本尊。reference复制的结果必然是两个reference指向同一块内存空间。
      
      虽然在方法中对于副本的操作并不会影响到本尊,但对内存空间的修改确实实实在在的,回到调用点,虽然本尊依然不知道曾经发生过的一切,但它按照原来的方式访问内存的时候,取到的确是经过方法修改之后的内容。于是方法可以把自己的影响扩展到方法之外。
      
      多说几句
      
      这个问题起源于我对C/C++中同样问题的思考。同C/C++相比,在changeReference中对reference赋值可能并不会造成什么很严重的后果,而在C/C++中,这么做却会造成臭名昭著的“内存泄漏”,根本的原因在于Java拥有了可爱的GC功能。即便这样,我仍不推荐使用这种的手法,毕竟GC已经很忙了,我们怎么好意思再麻烦人家。
      
      在C/C++中,这个问题还可以继续引申。既然在函数中对于指针直接赋值行不通,那么如何在函数中修改指针呢?答案很简单,指针的指针,也就是把原来的指针看作一个普通的数据,把一个指向它的指针传到函数中就可以了。
      
      同样的问题到了Java中就没有那么美妙的解决方案了,因为Java中可没有reference的reference这样的语法。可能的变通就是将reference进行封装成类。至于值不值,公道自在人心。

     

    http://www.iteye.com/topic/12961

     

     

      在 jdk 1.2 及其以后,引入了强引用、软引用、弱引用、虚引用这四个概念。网上很多关于这四个概念的解释,但大多是概念性的泛泛而谈,今天我结合着代码分析了一下,首先我们先来看定义与大概解释(引用类型在包 java.lang.ref 里)。
      1、强引用(StrongReference)
        强引用不会被GC回收,并且在java.lang.ref里也没有实际的对应类型。举个例子来说:
        Object obj = new Object();
        这里的obj引用便是一个强引用,不会被GC回收。
      2、软引用(SoftReference)
        软引用在JVM报告内存不足的时候才会被GC回收,否则不会回收,正是由于这种特性软引用在caching和pooling中用处广泛。软引用的用法:
    1     Object obj = new Object(); 
    2     WeakReference<Object> softRef = new WeakReference(obj); 
    3     // 使用 softRef.get() 获取软引用所引用的对象 
    4     Object objg = softRef.get();
      3、弱引用(WeakReference)
        当GC一但发现了弱引用对象,将会释放WeakReference所引用的对象。弱引用使用方法与软引用类似,但回收策略不同。
      4、虚引用(PhantomReference)
        当GC一但发现了虚引用对象,将会将PhantomReference对象插入ReferenceQueue队列,而此时PhantomReference所指向的对象并没有被GC回收,而是要等到ReferenceQueue被你真正的处理后才会被回收。虚引用的用法:
    1 Object obj = new Object(); 
    2 ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); 
    3 PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue); 
    4 // 调用phanRef.get()不管在什么情况下会一直返回null 
    5 Object objg = phanRef.get(); 
    6 // 如果obj被置为null,当GC发现了虚引用,GC会将phanRef插入进我们之前创建时传入的refQueue队列 
    7 // 注意,此时phanRef所引用的obj对象,并没有被GC回收,在我们显式地调用refQueue.poll返回phanRef之后 
    8 // 当GC第二次发现虚引用,而此时JVM将phanRef插入到refQueue会插入失败,此时GC才会对obj进行回收 
    9 Reference<? extends Object> phanRefP = refQueue.poll();
    看了简单的定义之后,我们结合着代码来测试一下,强引用就不用说了,软引用的描述也很清楚,关键是 “弱引用” 与 “虚引用”。
    弱引用:
    01 public static void main(String[] args) throws InterruptedException { 
    02     Object obj = new Object(); 
    03     ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); 
    04     WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue); 
    05     System.out.println(weakRef.get()); 
    06     System.out.println(refQueue.poll()); 
    07     obj = null; 
    08     System.gc(); 
    09     System.out.println(weakRef.get()); 
    10     System.out.println(refQueue.poll()); 
    11 }
    由于System.gc()是告诉JVM这是一个执行GC的好时机,但具体执不执行由JVM决定,因此当JVM决定执行GC,得到的结果便是(事实上这段代码一般都会执行GC):
      java.lang.Object@de6ced
      null
      null
      java.lang.ref.WeakReference@1fb8ee3
    从执行结果得知,通过调用weakRef.get()我们得到了obj对象,由于没有执行GC,因此refQueue.poll()返回的null,当我们把obj = null;此时没有引用指向堆中的obj对象了,这里JVM执行了一次GC,我们通过weakRef.get()发现返回了null,而refQueue.poll()返回了WeakReference对象,因此JVM在对obj进行了回收之后,才将weakRef插入到refQueue队列中。
    虚引用:
    01 public static void main(String[] args) throws InterruptedException { 
    02     Object obj = new Object(); 
    03     ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); 
    04     PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue); 
    05     System.out.println(phanRef.get()); 
    06     System.out.println(refQueue.poll()); 
    07     obj = null; 
    08     System.gc(); 
    09     System.out.println(phanRef.get()); 
    10     System.out.println(refQueue.poll()); 
    11 }
    同样,当JVM执行了GC,得到的结果便是:
      null
      null
      null
      java.lang.ref.PhantomReference@1fb8ee3
    从执行结果得知,我们先前说的没有错,phanRef.get()不管在什么情况下,都会返回null,而当JVM执行GC发现虚引用之后,JVM并没有回收obj,而是将PhantomReference对象插入到对应的虚引用队列refQueue中,当调用refQueue.poll()返回PhantomReference对象时,poll方法会先把PhantomReference的持有队列queue(ReferenceQueue<? super T>)置为NULL,NULL对象继承自ReferenceQueue,将enqueue(Reference paramReference)方法覆盖为return false,而此时obj再次被GC发现时,JVM再将PhantomReference插入到NULL队列中便会插入失败返回false,此时GC便会回收obj。事实上通过这段代码我们也的却看不出来obj是否被回收,但通过 PhantomReference 的javadoc注释中有一句是这样写的:
    Once the garbage collector decides that an object obj is phantom-reachable, it is being enqueued on the corresponding queue, but its referent is not cleared. That is, the reference queue of the phantom reference must explicitly be processed by some application code.
    翻译一下(这句话很简单,我相信很多人应该也看得懂):
    一旦GC决定一个“obj”是虚可达的,它(指PhantomReference)将会被入队到对应的队列,但是它的指代并没有被清除。也就是说,虚引用的引用队列一定要明确地被一些应用程序代码所处理。
    弱引用与虚引用的用处
      软引用很明显可以用来制作caching和pooling,而弱引用与虚引用呢?其实用处也很大,首先我们来看看弱引用,举个例子:
    1 class Registry { 
    2     private Set registeredObjects = new HashSet(); 
    3  
    4     public void register(Object object) { 
    5         registeredObjects.add( object ); 
    6     } 
    7 }
    所有我添加进 registeredObjects 中的object永远不会被GC回收,因为这里有个强引用保存在registeredObjects里,另一方面如果我把代码改为如下:
    1 class Registry { 
    2      private Set registeredObjects = new HashSet(); 
    3   
    4      public void register(Object object) { 
    5          registeredObjects.add( new WeakReference(object) ); 
    6      } 
    7  }
      现在如果GC想要回收registeredObjects中的object,便能够实现了,同样在使用HashMap如果想实现如上的效果,一种更好的实现是使用WeakHashMap。
    而虚引用呢?我们先来看看javadoc的部分说明:
    Phantom references are useful for implementing cleanup operations that are necessary before an object gets garbage-collected. They are sometimes more flexible than the finalize() method.
    翻译一下:
    虚引用在实现一个对象被回收之前必须做清理操作是很有用的。有时候,他们比finalize()方法更灵活。
    很明显的,虚引用可以用来做对象被回收之前的清理工作。

     

    转自:http://blog.sina.com.cn/s/blog_667ac0360102e9f3.html

    展开全文
  • 在dubbo springboot 使用时,在需要调用的服务接口上使用@Reference 即可直接调用远程服务 @Reference(version = "1.0.0", application = "${dubbo.application.id}") private HelloService helloService; 比如...
  • java:四种Reference的区别

    千次阅读 2016-03-18 10:44:37
    启动的时候要加上启动配置: -Xms10m -Xmx10m -verbose:gc 如果要使用Jconsole还要加上 :-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false ...
  • 一提到Reference 99.99%的java程序员都懵逼了",为啥改成汉字了呢?吐槽一下,因为CSDN出bug了,如果你用了%做标题,你的文章就别想用它的编辑器修改了,它的js脚本写的不够健壮,报错了;java.lang.ref....
  • Java篇 - 四种引用(Reference)实战

    千次阅读 2019-01-16 18:49:35
    Java的垃圾回收(GC)是虚拟机自动管理的,前面我有篇文章专门讲GC:《JVM篇 - GC给你整明白》 Java内存管理分为内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象。...
  • 假设两张表,表1(学号,姓名,性别),学号为主键. 表2(学号,课程,成绩). 可以为表2的学号定义外键(FOREIGN KEY),该外键的取值范围参照(REFERENCES)表1的学号 CONSTRAINT是对某列定义约束, 如上表1中的”性别”,可以定义...
  • 在实际编译代码的过程中,我们经常会遇到"undefined reference to"的问题,简单的可以轻易地解决,但有些却隐藏得很深,需要花费大量的时间去排查。工作中遇到了各色各样类似的问题,按照以下几
  • "undefined reference to" 问题解决方法

    万次阅读 多人点赞 2019-05-30 21:01:00
    (.text+0x13): undefined reference to `func’ 关于undefined reference 这样的问题,大家其实经常会遇到,在此,我以详细地示例给出常见错误的各种原因以及解决方法,希望对初学者有所帮助。 1. 链接时缺失了相关...
  • 描述:模块部分,写一个外部模块导入的时候居然提示unresolved reference,如下,程序可以正常运行,但是就是提示包部分红色,看着特别不美观,下面是解决办法 PyCharm版本: 解决: 1.在项目上 单击右键 -&...
  • Dubbo之@ReferenceReferenceBean

    千次阅读 2019-07-17 12:41:49
    1、构建一个ReferenceBean,然后使用Spring的@Autowired引用服务 @Bean public ReferenceBean<PLRepaymentPlanService> repaymentPlanServiceReferenceBean(){ ReferenceBean<PLRepayment...
  • java学习教程之Reference详解

    万次阅读 2017-01-24 22:06:14
    这是我们经常说的强引用StrongReference,jvm gc时会检测对象是否存在强引用,如果存在由根对象对其有传递的强引用,则不会对其进行回收,即使内存不足抛出OutOfMemoryError。 除了强引用外,Java还引入了...
  • 在进行unity游戏制作的C#代码编写时,会遇到“NullReferenceException: Object reference not set to an instance of an object”这样的错误提示。错误的意思翻译过来是“未将对象引用到对象的实例”,意思就是声明...
  • 注解Reference第一步:用Reference注解里的参数初始化ReferenceConfig 注解Reference第二步:从配置文件里获取参数,写入ReferenceConfig 注解Reference第三步:生成Consumer代理 解决方案 如果只想知道怎么解决...
  • unresolved reference",我就很郁闷,明明代码可以正确运行的啊,怎么会出现这种错误。 红色错误提示看着真心不爽,索性去网上百度了一圈,居然没找到解决办法,后来在stackoverflow上看到有人遇到同样...
  • java中的Reference类型

    千次阅读 2018-09-12 13:51:07
    本文简要总结java中的Reference类型。 最近在研读jdk并发框架,其中AQS是重点,由于我打破砂锅问到底的轻微强迫症,google了AQS作者Doug Lea的论文原文[The java.util.concurrent Synchronizer Framework],有...
  • 大猫品Android[三][Reference深入浅出]

    千次阅读 2016-06-07 22:42:59
    写在前面: Reference本身是一个接口,表示一个引用,不能直接使用,有四个它的派生类供我们使用,它们分别是:SoftReference,WeakReference,PhantomReference,FinalizerReference .其中SoftReference,...
  • JAVA中reference类型简述

    2013-03-30 16:01:40
    ReferenceQueue是一个队列(内部实现为一个Reference的列表),用于注册那些GC检测到不可达(即将会被回收)对象。  每个reference对象都可以"注册"相关的引用对象,当此对象即将回收(已经回收),将会把此r...
  • 内存管理 reference count

    千次阅读 2006-07-14 06:54:00
    reference count (引用计数)的概念其实很简单, 就是每个对象都有一个reference count 用来表明有多少其他的对象目前正保留一个对它的引用(reference). 对象A 想要引用对象B, A 就把B 的 reference count 加 1...
  • 实现了一个队列的入队(enqueue)和出队(poll还有remove)操作,内部元素就是泛型的Reference,并且Queue的实现,是由Reference自身的链表结构( 单向循环链表 )所实现的。 ReferenceQueue名义上是一个队列,但实际内部...
  • 引用(reference)和指针(pointer)是学C++过程中最令人头疼的问题,常常不知道什么时候用哪个合适,又常常弄混。找到Dan Saks的这篇文章,讲的很清楚,强烈推荐,所以翻译一下供大家参考。 ————————————...
  • 前言 上文中我们讲解了@Service注解的解析原理,了解到Dubbo默认支持两种方式进行解析,一种是通过springboot 自动配置来做的,另外一种是通过DubboComponentScan 注解来解析的,本文继续也是以DubboComponentScan ...
  • dubbo在controller中reference注解为空的问题深度解析

    万次阅读 多人点赞 2016-11-04 21:36:01
    dubbo注解的使用使用非常简单,下面贴出关键部分//provider的配置文件 <?xml version="1.0" encoding="UTF-8"?> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  • C:\msys\1.0\local\lib\libfltk.a(Fl_Group.o):Fl_Group.cxx:(.text$_ZN15Fl_Input_Choice7menu_cbEP9Fl_WidgetPv[__ZN15Fl_Input_Choice7menu_cbEP9Fl_WidgetPv]+0xfe)||undefined reference to `_Unwind_Resume'| ...
  • Reference类首先把内存分为4种状态Active,Pending,Enqueued,Inactive。 - Active,一般来说内存一开始被分配的状态都是 Active, - Pending 大概是指快要被放进队列的对象,也就是马上要回收的对象, - ...
  • 04-18 16:10:20.420: I/dalvikvm(13815): **JNI ERROR (app bug): accessed deleted global reference 0x1d5004ea** 04-18 16:10:20.420: E/dalvikvm(13815): VM aborting 04-18 16:10:20.420: A/libc(13815): ...
  • 由于Qt本身实现的机制所限,我们在使用Qt制作某些软件程序的时候,会遇到各种各样这样那样的问题,而且很多是很难,或者根本找不到原因的,即使解决了问题,如果有人问你为什么,你只能回答--不知道。...
  • Oracle Reference

    千次阅读 2004-08-18 15:29:00
    常用傻瓜问题1000问Oracle里的常用命令

空空如也

1 2 3 4 5 ... 20
收藏数 691,019
精华内容 276,407
关键字:

reference