转载:http://itindex.net/detail/47754-%E9%9D%A2%E8%AF%95-java-weakreference?utm_source=tuicool&utm_medium=referral

前言: 看到篇帖子, 国外一个技术面试官在面试senior java developer的时候, 问到一个weak reference相关的问题. 他没有期望有人能够完整解释清楚weak reference是什么, 怎么用, 只是期望有人能够提到这个concept和java的GC相关. 很可惜的是, 20多个拥有5年以上java开发经验的面试者中, 只有两人知道weak reference的存在, 而其中只有一人实际用到过他. 无疑, 在interviewer眼中, 对于weak reference的理解和应用在面试中给了这一个interviewee相当多的加分. 所以, 将我对于这个技术的理解和使用总结在这篇博客里, 希望读者和自己通过读和写这篇帖子, 能够在以后的工作和面试中获得加分.

在Java里, 当一个对象o被创建时, 它被放在Heap里. 当GC运行的时候, 如果发现没有任何引用指向o, o就会被回收以腾出内存空间. 或者换句话说, 一个对象被回收, 必须满足两个条件: 1)没有任何引用指向它 2)GC被运行.

在现实情况写代码的时候, 我们往往通过把所有指向某个对象的referece置空来保证这个对象在下次GC运行的时候被回收 (可以用java -verbose:gc来观察gc的行为)

Object c = new Car();
c=null;

但是, 手动置空对象对于程序员来说, 是一件繁琐且违背自动回收的理念的.  对于简单的情况, 手动置空是不需要程序员来做的, 因为在java中, 对于简单对象, 当调用它的方法执行完毕后, 指向它的引用会被从stack中popup, 所以他就能在下一次GC执行时被回收了.

但是, 也有特殊例外. 当使用cache的时候, 由于cache的对象正是程序运行需要的, 那么只要程序正在运行, cache中的引用就不会被GC给(或者说, cache中的reference拥有了和主程序一样的life cycle). 那么随着cache中的reference越来越多, GC无法回收的object也越来越多, 无法被自动回收. 当这些object需要被回收时, 回收这些object的任务只有交给程序编写者了. 然而这却违背了GC的本质(自动回收可以回收的objects).

所以, java中引入了weak reference. 相对于前面举例中的strong reference:

Object c = new Car(); //只要c还指向car object, car object就不会被回收

当一个对象仅仅被weak reference指向, 而没有任何其他strong reference指向的时候, 如果GC运行, 那么这个对象就会被回收. weak reference的语法是:

WeakReference<Car> weakCar = new WeakReference(Car)(car);

当要获得weak reference引用的object时, 首先需要判断它是否已经被回收:

weakCar.get();

如果此方法为空, 那么说明weakCar指向的对象已经被回收了.

下面来看一个例子:

package weakreference;
/**
* @author wison
*/
public class Car {
private double price;
private String colour; public Car(double price, String colour){
this.price = price;
this.colour = colour;
} public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getColour() {
return colour;
}
public void setColour(String colour) {
this.colour = colour;
} public String toString(){
return colour +"car costs $"+price;
} }
package weakreference;

import java.lang.ref.WeakReference;

/**
* @author wison
*/
public class TestWeakReference { public static void main(String[] args) { Car car = new Car(22000,"silver");
WeakReference<Car> weakCar = new WeakReference<Car>(car); int i=0; while(true){
if(weakCar.get()!=null){
i++;
System.out.println("Object is alive for "+i+" loops - "+weakCar);
}else{
System.out.println("Object has been collected.");
break;
}
}
} }

在上例中, 程序运行一段时间后, 程序打印出"Object has been collected." 说明, weak reference指向的对象的被回收了.

值得注意的一点, 即使有 car引用指向对象, 且 car是一个strong reference, weak reference weakCar指向的对象仍然被回收了. 这是因为java的编译器在发现进入while循环之后, car已经没有被使用了, 所以进行了优化(将其置空?). 当把TestWeakReference.java修改为:

package weakreference;

import java.lang.ref.WeakReference;

/**
* @author wison
*/
public class TestWeakReference { public static void main(String[] args) { Car car = new Car(22000,"silver");
WeakReference<Car> weakCar = new WeakReference<Car>(car); int i=0; while(true){
System.out.println("here is the strong reference 'car' "+car);
if(weakCar.get()!=null){
i++;
System.out.println("Object is alive for "+i+" loops - "+weakCar);
}else{
System.out.println("Object has been collected.");
break;
}
}
} }

weak reference指向的object就不会被回收了. 因为还有一个strong reference car指向它.

* WeakReference的一个特点是它何时被回收是不可确定的, 因为这是由GC运行的不确定性所确定的. 所以, 一般用weak reference引用的对象是有价值被cache, 而且很容易被重新被构建, 且很消耗内存的对象.

ReferenceQueue

在weak reference指向的对象被回收后, weak reference本身其实也就没有用了. java提供了一个ReferenceQueue来保存这些所指向的对象已经被回收的reference. 用法是在定义WeakReference的时候将一个ReferenceQueue的对象作为参数传入构造函数.

其他类型的references

-SoftReference

soft reference和weak reference一样, 但被GC回收的时候需要多一个条件: 当系统内存不足时(GC是如何判定系统内存不足? 是否有参数可以配置这个threshold?), soft reference指向的object才会被回收. 正因为有这个特性, soft reference比weak reference更加适合做cache objects的reference. 因为它可以尽可能的retain cached objects, 减少重建他们所需的时间和消耗.

-phantomReference

这个还没想到应用场景, 就先不说了. 有人在实践中用到了的话, 欢迎分享.

WeakHashMap

to be continued

Java WeakReference的理解与使用的更多相关文章

  1. Java基础之理解Annotation(与@有关,即是注释)

    Java基础之理解Annotation 一.概念 Annontation是Java5开始引入的新特征.中文名称一般叫注解.它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata) ...

  2. Java 集合深入理解(8):AbstractSequentialList

    点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天有点无聊,来学学 AbstractSequentialList 解解闷 吧! AbstractSequentialLi ...

  3. Java 集合深入理解(7):ArrayList

    点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天心情有点美丽,学学 ArrayList 放松下吧! 什么是 ArrayList ArrayList 是 Java 集合 ...

  4. Java 集合深入理解(4):List<E> 接口

    点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 蓝瘦!香菇! 连着加班几天,醉了.学学 List 放松下! 在 Java 集合深入理解:Collection 中我们熟悉了 ...

  5. java线程安全理解

    java线程安全理解 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. ...

  6. java常量池理解

    String类两种不同的创建方式 String s1 = "zheng"; //第一种创建方式 String s2 = new String("junxiang" ...

  7. java多线程的理解

    java多线程的理解   线程的5种状态:新建,就绪,运行,阻塞,死亡. Thread.sleep:线程  运行状态 转为  阻塞状态,(其它线程启动运行) Thread.yield:   线程 运行 ...

  8. 学习java的阶段性理解(其它语言也一样)

    打算从今天开始学java啊,待会滚去找资料了.现在谈一下学习java阶段性的理解.由于现在对java真的啥也不知道啊,不过还是要瞎鸡儿写点自己的看法,以下看法应该也使适用于其它语言: 第一阶段,入门级 ...

  9. 谈谈你对 Java 平台的理解

    声明 本篇所涉及的提问,正文的知识点,全都来自于杨晓峰的<Java核心技术36讲>,当然,我并不会全文照搬过来,毕竟这是付费的课程,应该会涉及到侵权之类的问题. 所以,本篇正文中的知识点, ...

随机推荐

  1. live555源码研究(十)------在编译过程中遇到的问题及解决方法

    一.编译testOnDemandRTSPServer.cpp. 在testProgs项目中,加入testOnDemandRTSPServer.cpp进行编译,编译类型是编译成exe文件,在编译过程中会 ...

  2. 解决 IntelliJ 乱码问题

    原文:解决 IntelliJ 乱码问题 汉字符在IntelliJ的控制台输出乱码.编译器在编译的时候,把汉字符编译成非UTF-8而引起乱码.我是在做Jsoup解析的时候出现的错误,其实归根结底确实编译 ...

  3. SRM589

    250: 给一个串S,可以做这样的操作,可以将串中的一种字母变成另一种字母,代价是该种字母的数量.求解的问题是,最小的代价将串S变成回文串. 根据回文关系,我们可以形成等价对应关系,a与b等价对应说明 ...

  4. !! Scrum之 流程和术语

    !!Scrum之 流程和术语 http://www.cnblogs.com/zhoujg/archive/2009/07/15/1523680.html 以下将对一些术语进行简单介绍,以便大家现在开始 ...

  5. WinCE NAND flash - FAL

    http://blog.csdn.net/renpine/article/details/4572347 http://msdn.microsoft.com/en-US/library/ee48203 ...

  6. hadoop博客 oschina

    http://my.oschina.net/Xiao629/blog?catalog=449279

  7. poj 1265 Area( pick 定理 )

    题目:http://poj.org/problem?id=1265 题意:已知机器人行走步数及每一步的坐标   变化量 ,求机器人所走路径围成的多边形的面积.多边形边上和内部的点的数量. 思路:1.以 ...

  8. 大四实习准备5_android广播机制

    2015-5-1 android 广播机制 5.1简介 分为标准广播(Normal broadcasts)(无先后顺序,几乎同时接收,不可截断)和有序广播(Ordered broadcasts)(有先 ...

  9. UVa 1645 (递推) Count

    题意: 有多少个n个节点的有根树,满足每层节点的子节点个数相同,输出该数目除以1e9+7的余数. 分析: 这种题目就属于那种,看起来很高冷,读完题更高冷.想了N久想不出来,一搜题解,卧槽,这么sb的题 ...

  10. Gentoo源码安装图解

    Gentoo源码安装 一.前期准备 (1)下载以下三个文件 二.配置安装环境 (1)用光盘引导到LiveCD环境 (2)配置当前LiveCD环境的网络 安装Gentoo时,服务器引导的LiveCD环境 ...