java程序员应该知道的两种引用

转载 2012年03月21日 16:26:45
 java中没有指针,到处都是引用(除了基本类型)。所以,当然,你肯定知道java的引用,并用了很久,但是是不是对此了解地比较全面?而这些引用有什么作用,且有什么不同呢?
Java中有个java.lang.ref包,这里面都是描述引用对象的,包括了Reference,SoftReference,WeakReference和PhantomReference。其中,Reference是基类其他三个类的基类。下面就这几种引用对象做个说明。

强引用(Strong References)
我们每天都在用强引用(如果你每天都在用java的话),一段如下的代码:
HashMap mapRef = new HashMap();
就是通过new HashMap();创建了一个对象(这东西在heap上),并把一个强引用存到了 mapRef引用中。而强引用之为“强”的地方就在于其对垃圾回收器所产生的影响。如果一个对象可以经由一条强引用链可达(也就说这个对象是Strongly reachable),那么就说明这个类不适合被垃圾回收。我们也绝对不希望正在使用的对象一下子了无踪迹了。

但是强引用会对我们的应用产生很“强”的影响。比如:经常会碰到一个问题,缓存。通过Set(以set为例吧)模拟的缓存,在应用运行的过程中,会不断有大量对象添加到set中。这些对象并不会被GC回收,并且随着对象的增多,我们的内存也会不断变大,终于有一天OutOfMemory啦。其实,set可能使用频率还不大,HashMap的key-value模式让我们爱不释手,引诱着你去不断地put,put,扑通。。OutOfMemory啦。
对于java这门有魅力,有活力,有朝气,有老气,有垃圾自动回收机制的语言而言,我们不应被上述问题所困扰。

弱引用(Weak Reference)
弱引用,就是不是那种用强制的方式要求对象存在于内存的引用。可以借助垃圾回收器来判断某个对象的可达性,并帮你回收弱引用所引用的对象。如何创建一个弱引用呢:
StringBuffer sbuff = new StringBuffer("What is a WeakReference?");
WeakReference<StringBuffer> wref = new WeakReference<StringBuffer>(sbuff);

sbbuff=null;//这里的操作,看情况定。在这里主要为了说明,原来强引用的一个对象,被转成一个弱引用来指向。
然后通过wref.get()来获取sbuff对象。因为弱引用并没强悍到可以阻止垃圾回收器回收wref引用的对象(这里要区分引用对象和被引用的对象,在创建一个 WeakReference时,就有一个引用对象诞生了,它指向了一个被引用的对象),所以可能从某一刻开始,wref.get()就开始给我们null了。
对于上面提到的使用HashMap时,对象过多(并且不删除,而被垃圾回收)会造成的OutOfMemory问题,可以通过WeakHashMap来实现,这样垃圾回收器就会帮我们处理那些时间长了不用,还占地方的类了,而不至于出现OutOfMemory问题。

引用队列( ReferenceQueue,何方神圣?)
当WeakReference开始返回null时,说明它原来指向的对象已经变成了垃圾。另外也说明这个WeakReference对我们已经没多少用处了。我们需要做点什么来处理这些没用的东西?
逢此危难之际,ReferenceQueue闪亮登场。据官方资料,其定义为:
Reference queues, to which registered reference objects are appended by the garbage collector after the appropriate reachability changes are detected.
(当检测到相应的可达性发生改变后,垃圾回收器就会将注册有此队列的引用对象添加到这个引用队列中。)
如何注册一个队列?在WeakReference的构造函数中,有一个WeakReference(T referent, ReferenceQueue<? super T> q)。所以,当一个WeakReference变成一个死引用时,它就会被添加到这个ReferenceQueue中,只要定期的来处理一下这个ReferenceQueue就可以了。

不同的引用

引用实际上是有好几种的,就如我们在java.lang.ref包中看到的那样,再加上强引用,有4种引用类型:强(Strong)、软(Soft)、弱(Weak)、幻象(Phantom),引用依次从强到弱。接下来,就看看其他的引用。

软引用(Soft Reference)

软引用,跟弱引用功能挺像的。但是软引用指向的对象一般会比弱引用的存活时间长一些,直到内存空间不够时,才会被垃圾回收。一个Weakly reachable对象,是仅仅被WeakReference引用的,并且会被垃圾回收器在下一个垃圾回收周期中丢弃;而一个Softly reachable对象,则会活地时间长一些。

软引用给我们带来了很大的实惠,尤其是缓存的实现。比如,我们有一个缓存池,对于内存比较紧张的情况来说,一旦要达到memory上限时,垃圾回收器就将Soft Reference引用的对象释放掉,以避免OutOfMemory惨剧的发生。

幻象引用(Phantom Reference)

幻象引用,是不同于Soft和Weak的引用。幻象引用对指向对象的引用强度如此之脆弱,以至于调用方法get()时,总是返回null。它的主要作用就是跟踪所指向的对象已经dead了,那么其跟WeakReference的区别是什么呢?

它们的区别就在于:是在什么时候,这个引用对象被添加到引用队列中的。WeakReference是在当其所引用的对象变成Weakly Reachable时被添加到引用队列中的,这发生在一个对象被finalization或被垃圾回收之前的。理论上讲,一个对象在被finalize()时,是可以被“复活”的,但此时WeakReference已经没活力了。对幻象引用来说,只有当其所引用的对象被彻底垃圾回收(从内存中消除)时,才会添加到引用队列中。而幻象引用的get方法总是返回null,就是要避免我们来“复活”一个奄奄一息的对象。

那么幻象引用有何实际作用?

第一、我们可以在监控一个对象什么时候被彻底销毁了。那样,就可以做点什么其他事情(看你是不是有这方面的需求啦)。不过实际中,这种情况也不多的。

第二、因为理论上存在的,可以通过一个对象的finalize()方法“复活”一个对象,那么如果在一次垃圾回收处理时,调用了一个对象的finalize()(这个方法在何时调用不确定),却让它复活了。要再苦苦等待finalize()的执行,还不知道要到猴年马月的(天下大赦可以有,但不是天天有。谁知道啥时候天朝更替,人主易位)。突然就出现了OutOfMemory错误了。

而幻象引用绝对不会再让对象复活,只要被它逮着了,事情就简单了:挂定了!

总而言之,言而总之,归根结底:

引用是关系垃圾回收的。

读《程序员应该知道的97件事》笔记

1.技术债务和童子军规则 技术债务 当你发现必须在“干得好”和“干得快”之间做出抉择的时候,一般都会选择“干得快”,并提醒自己将来再来返工。下一轮迭代自有其新的问题,工作重点转移到新问题上,老问题还存...
  • lsblsb
  • lsblsb
  • 2013年12月18日 19:41
  • 906

《程序员应该知道的97件事》

  《程序员应该知道的97件事》 False consensus bias 虚假同感偏差 柏拉图:风格之美、和谐、优雅及优美的节奏,尽在于简单 童子军规则:尽力去...
  • lllcfr1
  • lllcfr1
  • 2014年08月11日 23:36
  • 637

《那些年啊,那些事——一个程序员的奋斗史》——97

如果想和领导套套近乎,了解上级的想法,那就是要意无意地和领导多接触。当然这并不需要很正式的场合,也不需要一本正经地讨论,只需要像聊天一样唠唠嗑。最合适的场合便是在电梯,时间不长也不短,但如果下属把握好...
  • norains
  • norains
  • 2012年05月12日 10:04
  • 30372

[转帖]想成为嵌入式程序员应知道的16个基本问题

  这是嵌入式C程序员的基本知识。作者在Embedded Systems Programming杂志上发表了很多嵌入式系统开发方面的文章。  C语言测试是招聘嵌入式系统程序员过程中必须而且有效的方法。...
  • xiaocai0001
  • xiaocai0001
  • 2006年04月13日 21:25
  • 5440

每个程序员应该知道的计算机网络知识

因特网 因特网是当今世界上最大的网络, 是”网络的网络”. 即因特网是所有网络互连起来的一个巨型网络. 因特网的组成 : 边缘部分 : 主机 核心部分 : 大量网络和连接这些网络的路由器(此路...
  • Doraemon___
  • Doraemon___
  • 2016年12月06日 19:36
  • 1103

开发者需要知道的有关软件架构的五件事

1.软件架构不只是前期的“大设计” 传统的观点认为,软件架构就是在前期进行“大设计”,然后通过瀑布模型进行交付,架构团队要确保软件的每一个元素在进行编码之前都要考虑妥当。2001年,“敏捷开发宣...
  • qq_41077703
  • qq_41077703
  • 2018年01月23日 14:26
  • 148

新入行程序员必须知道的十个秘密

1、版本控制系统(VCS)   VCS 也许是计算机课程最大的疏漏。这些课程光记得教如何写代码,但却往往忘记教学生如何去管理代码。   每一个程序员都应该懂得利用 Git 或 Subversion...
  • baidu_35738377
  • baidu_35738377
  • 2016年10月27日 10:44
  • 801

程序员应该了解的测试

工作两年了,我一直希望让自己每年对测试的理解更深入一层。工作一年的时候我写了《谈软件测试---一年工作总结》 ,谈轮了自己对各种测试的理解,这一年来,虽然对那些理概念的有所加强,自我感觉没有什么质的变...
  • oufua
  • oufua
  • 2015年07月26日 20:11
  • 444

Java程序员应该掌握的Linux知识

最近在学Linux,因为以后要做Java开发,所以想了解下Linux需要掌握哪些技能,掌握到什么程度。在网上搜了很久,也没有明确的说法,所以我就自己整理出来一份,供大家参考,同时我也按照这个list来...
  • sinat_27389893
  • sinat_27389893
  • 2017年06月03日 08:23
  • 296

一个程序员应该知道的名词

dns   (域名系统)   DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器...
  • qq_35549405
  • qq_35549405
  • 2017年06月19日 11:15
  • 840
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java程序员应该知道的两种引用
举报原因:
原因补充:

(最多只允许输入30个字)