当前位置:首页 > 开发 > 编程语言 > Java > 正文

理解Java中的弱引用

发表于: 2014-12-31   作者:tomcat_oracle   来源:转载   浏览:
摘要:  不久之前,我 面试了一些求职Java高级开发工程师的应聘者。我常常会面试他们说,“你能给我介绍一些Java中得弱引用吗?”,如果面试者这样说,“嗯,是不是垃圾回收有关的?”,我就会基本满意了,我并不期待回答是一篇诘究本末的论文描述。   然而事与愿违,我很吃惊的发现,在将近20多个有着平均5年开发经验和高学历背景的应聘者中,居然只有两个人知道弱引用的存在,但是在这两个人之中只有一个人真正了
 不久之前,我 面试了一些求职Java高级开发工程师的应聘者。我常常会面试他们说,“你能给我介绍一些Java中得弱引用吗?”,如果面试者这样说,“嗯,是不是垃圾回收有关的?”,我就会基本满意了,我并不期待回答是一篇诘究本末的论文描述。
  然而事与愿违,我很吃惊的发现,在将近20多个有着平均5年开发经验和高学历背景的应聘者中,居然只有两个人知道弱引用的存在,但是在这两个人之中只有一个人真正了解这方面的知识。在面试过程中,我还尝试提示一些东西,来看看有没有人突然说一声“原来是这个啊”,结果很是让我失望。我开始困惑,为什么这块的知识如此不被重视,毕竟弱引用是一个很有用途的特性,况且这个特性已经在7年前 Java 1.2发布时便引入了。
  好吧,这里我不期待你看完本文之后成为一个弱引用方面的专家,但是我认为至少你应该了解什么是弱引用,如何使用它们,并且什么场景使用。既然它们是一些不知名的概念,我简单就着前面的三个问题来说明一下。
   强引用(Strong Reference)
  强引用就是我们经常使用的引用,其写法如下
  StringBuffer buffer = new StringBuffer();
  上面创建了一个StringBuffer对象,并将这个对象的(强)引用存到变量buffer中。是的,就是这个小儿科的操作(请原谅我这样的说法)。强引用最重要的就是它能够让引用变得强(Strong),这就决定了它和垃圾回收器的交互。具体来说,如果一个对象通过一串强引用链接可到达(Strongly reachable),它是不会被回收的。如果你不想让你正在使用的对象被回收,这就正是你所需要的。
   但是强引用如此之强
  在一个程序里,将一个类设置成不可被扩展是有点不太常见的,当然这个完全可以通过类标记成final实现。或者也可以更加复杂一些,就是通过内部包含了未知数量具体实现的工厂方法返回一个接口(Interface)。举个例子,我们想要使用一个叫做Widget的类,但是这个类不能被继承,所以无法增加新的功能。
  但是我们如果想追踪Widget对象的额外信息,我们该怎么办? 假设我们需要记录每个对象的序列号,但是由于Widget类并不包含这个属性,而且也不能扩展导致我们也不能增加这个属性。其实一点问题也没有,HashMap完全可以解决上述的问题。
  serialNumberMap.put(widget, widgetSerialNumber);
  这表面看上去没有问题,但是widget对象的强引用很有可能会引发问题。我们可以确信当一个widget序列号不需要时,我们应该将这个条目从map中移除。如果我们没有移除的话,可能会导致内存泄露,亦或者我们手动移除时删除了我们正在使用的widgets,会导致有效数据的丢失。其实这些问题很类似,这就是没有垃圾回收机制的语言管理内存时常遇到的问题。但是我们不用去担心这个问题,因为我们使用的时具有垃圾回收机制的Java语言。
  另一个强引用可能带来的问题就是缓存,尤其是像图片这样的大文件的缓存。假设你有一个程序需要处理用户提供的图片,通常的做法就是做图片数据缓存,因为从磁盘加载图片代价很大,并且同时我们也想避免在内存中同时存在两份一样的图片数据。
  缓存被设计的目的就是避免我们去再次加载哪些不需要的文件。你会很快发现在缓存中会一直包含一个到已经指向内存中图片数据的引用。使用强引用会强制图片数据留在内存,这就需要你来决定什么时候图片数据不需要并且手动从缓存中移除,进而可以让垃圾回收器回收。因此你再一次被强制做垃圾回收器该做的 工作,并且人为决定是该清理到哪一个对象。
   弱引用(Weak Reference)
  弱引用简单来说就是将对象留在内存的能力不是那么强的引用。使用WeakReference,垃圾回收器会帮你来决定引用的对象何时回收并且将对象从内存移除。创建弱引用如下
  WeakReference<Widget> weakWidget = new WeakReference<Widget>(widget);
  使用weakWidget.get()就可以得到真实的Widget对象,因为弱引用不能阻挡垃圾回收器对其回收,你会发现(当没有任何强引用到widget对象时)使用get时突然返回null。
  解决上述的widget序列数记录的问题,最简单的办法就是使用Java内置的WeakHashMap类。WeakHashMap和HashMap几乎一样,唯一的区别就是它的键(不是值!!!)使用WeakReference引用。当WeakHashMap的键标记为垃圾的时候,这个键对应的条目就会自动被移除。这就避免了上面不需要的Widget对象手动删除的问题。使用WeakHashMap可以很便捷地转为HashMap或者Map。
引用队列(Reference Queue)
  一旦弱引用对象开始返回null,该弱引用指向的对象就被标记成了垃圾。而这个弱引用对象(非其指向的对象)就没有什么用了。通常这时候需要进行一些清理工作。比如WeakHashMap会在这时候移除没用的条目来避免保存无限制增长的没有意义的弱引用。
  引用队列可以很容易地实现跟踪不需要的引用。当你在构造WeakReference时传入一个ReferenceQueue对象,当该引用指向的对象被标记为垃圾的时候,这个引用对象会自动地加入到引用队列里面。接下来,你就可以在固定的周期,处理传入的引用队列,比如做一些清理工作来处理这些没有用的引用对象。
   四种引用
  Java中实际上有四种强度不同的引用,从强到弱它们分别是,强引用,软引用,弱引用和虚引用。上面部分介绍了强引用和弱引用,下面介绍剩下的两个,软引用和虚引用。
  软引用(Soft Reference)
  软引用基本上和弱引用差不多,只是相比弱引用,它阻止垃圾回收期回收其指向的对象的能力强一些。如果一个对象是弱引用可到达,那么这个对象会被垃圾回收器接下来的回收周期销毁。但是如果是软引用可以到达,那么这个对象会停留在内存更时间上长一些。当内存不足时垃圾回收器才会回收这些软引用可到达的对象。
  由于软引用可到达的对象比弱引用可达到的对象滞留内存时间会长一些,我们可以利用这个特性来做缓存。这样的话,你就可以节省了很多事情,垃圾回收器会关心当前哪种可到达类型以及内存的消耗程度来进行处理。
   虚引用 (Phantom Reference)
  与软引用,弱引用不同,虚引用指向的对象十分脆弱,我们不可以通过get方法来得到其指向的对象。它的唯一作用就是当其指向的对象被回收之后,自己被加入到引用队列,用作记录该引用指向的对象已被销毁。
  当弱引用的指向对象变得弱引用可到达,该弱引用就会 〱会自用、虚,; maq-hecommen/前哪ponse虚有一个人真正了" />
mmary"> ="1676 ar- tarblog-co; f>当div cl章x;"> < am0t="16766c.h jrhtze: 14px;"> _0.c_e.baiv cl章blog-co; font-weighle="line-hei ararblog-co; font-w fo /div> _0.c="16766c.href="/ fooooo fooooo fooooo le="line-heisus: t_0.c_c.
_0.c_g/ib/ta2面16766c.href="/ fooo工作" >"> <4625591image/pa> 前,我 面试了一 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh fooooole="line-heisus: t_0.c_c.
_0.c_g/ib/ta3面16766c.href="/ fooo工作" >"> <49377/image/pa>留言板nntent00381 1,下面介绍 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh fooooole="line-heisus: t_0.c_c.
_0.c_g/ib/ta4面16766c.href="/ fooo工作" >"> <4777 image/pa>留言板 1自用〱被标记 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh fooooole="line-heisus: t_0.c_c.
_0.c_g/ib/ta5面16766c.href="/ fooo工作" >"> <1com/nct"/web/ (笔ght: 留言板 :
_0.c_g/ib/ta6面16766c.href="/ fooo工作" >"> <690 t"/web/ (笔ght: 10 留言板 : 10
_0.c_g/ib/ta7面16766c.href="/ fooo工作" >"> <20 75t"/web/ (笔ght: 10 留言板 : 10
_0.c_g/ib/ta8面16766c.href="/ fooo工作" >"> <3533757t"/web/ (0381 10 留言板0381 10
_0.c_g/ib/ta9面16766c.href="/ fooo工作" >"> <3761107t"/web/ (0381 10 留言板0381 10 _0.c_g/ib/ta10面16766c.href="/ fooo工作" >"> <428889 image/pa>留言板0381 10 _0.c_g/ib/ta11面16766c.href="/ fooo工作" >"> <4351283t"/web/ (笔ght0 留言板 0 _0.c_g/ib/ta12面16766c.href="/ fooo工作" >"> <45bLo33t"/web/ (0381 10 留言板0381 10 _0.c_={"co="16766c.href="/ fooo _0.c_g/ib/ta13面16766c.href="/ fooo工作" >"> <1635ct"/web/ (笔ght: 10commen,下面䈰其指ank">留言板 1自用』,下面䈰其指 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh fooooole="line-heisus: t_0.c_c. _0.c_g/ib/ta14面16766c.href="/ fooo工作" >"> <7968/image/i用 e象㏯吋绍剩下的两个ank">留言板0381 1,下面介绍剩下的两个 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh fooooole="line-heisus: t_0.c_c. _0.c_g/ib/ta15面16766c.href="/ fooo工作" >"> <2111t"/web/ (笔ght: 10commen长一事的两个ank">留言板 1自用〼长一事的两个 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh fooooole="line-heisus: t_0.c_c. _0.c_g/ib/ta16面16766c.href="/ fooo工作" >"> <1175843t"/web/ (笔ght 1,下面介绍剩䏯ommend4"> 1,下面介绍剩䏯ommend4" 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh fooooole="line-heisus: t_0.c_c. _0.c_g/ib/ta17面16766c.href="/ fooo工作" >"> <1120888t"/web/ (0381 10象:ine-h(e象 妺引用链接ank">留言板0381 1e象:ine-h(e象 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh fooooole="line-heisus: t_0.c_c. _0.c_g/ib/ta18面16766c.href="/ fooo工作" >"> <32547 t"/web/ (0381 1,下面介绍剩gin: 10px 0pank">留言板0381 1,下面介绍剩gin: 10px 0p 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh fooooole="line-heisus: t_0.c_c. _0.c_g/ib/ta19面16766c.href="/ fooo工作" >"> <3o33145t"/web/ (笔ght: 10commen,下面䈰其指ank">留言板 1自用』,下面䈰其指 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh fooooole="line-heisus: t_0.c_c. _0.c_g/ib/ta20面16766c.href="/ fooo工作" >"> <37-se75t"/web/ (0381 1,下面介绍剩gin: 10px 0pank">留言板0381 1,下面介绍剩gin: 10px 0p 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ foblog-co; font-weigh foblog-co; font-weigblog-co; font-blog-co; f>当div cl章x"text/javas i; fobmmary"> <旦d --> *at:吏侧栏000*/16766c.hr{})[cpro_id = ={a .01rsi; fofooo> fooo #33i; fobADx"text/javasci; f ar- tarblog-co; f>当div cl章2x;"> < am0t="16766c.h jrhtze: 14px;"> _0.2_e.ba编辑iv clblog-co; font-weig旦d --> < ararblog-co; font-w fo /div> _0.target="_blank"> le="line-heisus: t_0.2_c. _0.2_g/ib/ta1面16766c.href="/ fooo工作" >"> <10.com/image/i用 (ecommend4"> 0381 1|(ecommend4" 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ fooommary"> _0.2_ctar 0381 10
_0.2_c.
_0.2_g/ib/ta2面16766c.href="/ fooo工作" >"> <26的弱引用 (笔记)
_0.2_ctar 绍剩下皨,下鈩较樋 <0blog-cfooooooooooooooooooo16766c.href="/ foblog-co; font-weigooooooommary"> _0.2_c.
_0.2_g/ib/ta3面16766c.href="/ fooo工作" >"> <软(弱)引用
_0.2_ctar 0381 10
_0.2_c. _0.2_={"co="16766c.href="/ fooo
_0.2_g/ib/ta4面16766c.href="/ fooo工作" >"> <26arget="_blank">JAVA中的强引用、弱引用、软引用、虚引用
_0.2_ctar 1./r/cm: 10
_0.2_c.
_0.2_g/ib/ta5面16766c.href="/ fooo工作" >"> <2弱引用
_0.2_g/ib/ta6面16766c.href="/ fooo工作" >"> < 63 image/pa>
留言板 ,下 0commen 关 516766c.href="/ fooo   fooooo fooooo fooo16766c.href="/ fooommary"> _0.2_ctar 1 _0.2_c. _0.2_g/ib/ta7面16766c.href="/ fooo工作" >"> <2295497t"/web/ (7px:0381: 10 7px:0381: 10 _0.2_ctar rc=JDK697eigh _0.2_c. _0.2_g/ib/ta8面16766c.href="/ fooo工作" >"> <243409 image/pa>留言板03810 _0.2_ctar 1 _0.2_c. _0.2_={"co="16766c.href="/ fooo _0.2_g/ib/ta9面16766c.href="/ fooo工作" >"> <238973/image/i用留言板0381 00000381 _0.2_ctar 1./r/cm: 10
_0.2_c.
_0.2_={"co="16766c.href="/ fooo _0.2_g/ib/ta10面16766c.href="/ fooo工作" >"> <2622106t"/web/ (0381 00000381 留言板0381 00000381 _0.2_ctar 1./r/cm: 10
blog-cfooo当ad ; fo i; fo) #33mmary"> href="/">首毫 5 -oi; foba v> href="/aboutt"/we>关蜁了 5 -oi; foba utbsp;|&nSetHome0:"650".location)"href=" >偸首毫 5 -oi; foba utbsp;|&nAddFavor 0:"650".location,document.={"co)"href=" >正/21. 5 -oi; foba v> href="//div> /image>样搜索 5 -oi; foba v> href="// 000xml">S 00 516766blog-co; fobmmary"> >京ICP备090 3238 5
blog-cfo)bodyt10""/wl>