Java 中的 Reference

来源:互联网 发布:淘宝网休闲外套女装 编辑:程序博客网 时间:2024/05/17 01:02

======================================================
注:本文源代码点此下载
======================================================

在 jdk 1.2 及其以后,引入了强引用、软引用、弱引用、虚引用这四个概念。网上很多关于这四个概念的解释,但大多是概念性的泛泛而谈,今天我结合着代码分析了一下,首先我们先来看定义与大概解释(引用类型在包 java.lang.ref 里)。

1、强引用(strongreference)

强引用不会被gc回收,并且在java.lang.ref里也没有实际的对应类型。举个例子来说:

object obj = new object();

这里的obj引用便是一个强引用,不会被gc回收。

2、软引用(softreference)

软引用在jvm报告内存不足的时候才会被gc回收,否则不会回收,正是由于这种特性软引用在caching和pooling中用处广泛。软引用的用法:

object obj = new object();

softreference softref = new softreference(obj);

// 使用 softref.get() 获取软引用所引用的对象

object objg = softref.get();

3、弱引用(weakreference)

当gc一但发现了弱引用对象,将会释放weakreference所引用的对象。弱引用使用方法与软引用类似,但回收策略不同。

4、虚引用(phantomreference)

当gc一但发现了虚引用对象,将会将phantomreference对象插入referencequeue队列,而此时phantomreference所指向的对象并没有被gc回收,而是要等到referencequeue被你真正的处理后才会被回收。虚引用的用法:

object obj = new object();

referencequeue refqueue = new referencequeue();

phantomreference phanref = new phantomreference(obj, refqueue);

// 调用phanref.get()不管在什么情况下会一直返回null

object objg = phanref.get();

// 如果obj被置为null,当gc发现了虚引用,gc会将phanref插入进我们之前创建时传入的refqueue队列

// 注意,此时phanref所引用的obj对象,并没有被gc回收,在我们显式地调用refqueue.poll返回phanref之后

// 当gc第二次发现虚引用,而此时jvm将phanref插入到refqueue会插入失败,此时gc才会对obj进行回收

reference phanrefp = refqueue.poll();

看了简单的定义之后,我们结合着代码来测试一下,强引用就不用说了,软引用的描述也很清楚,关键是 “弱引用” 与 “虚引用”。

弱引用:

public static void main(string[] args) throws interruptedexception {

object obj = new object();

referencequeue refqueue = new referencequeue();

weakreference weakref = new weakreference(obj, refqueue);

system.out.println(weakref.get());

system.out.println(refqueue.poll());

obj = null;

system.gc();

system.out.println(weakref.get());

system.out.println(refqueue.poll());

}

由于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队列中。

虚引用:

public static void main(string[] args) throws interruptedexception {

object obj = new object();

referencequeue refqueue = new referencequeue();

phantomreference phanref = new phantomreference(obj, refqueue);

system.out.println(phanref.get());

system.out.println(refqueue.poll());

obj = null;

system.gc();

system.out.println(phanref.get());

system.out.println(refqueue.poll());

}

同样,当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)置为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,而弱引用与虚引用呢?其实用处也很大,首先我们来看看弱引用,举个例子:

class registry {

private set registeredobjects = new hashset();

public void register(object object) {

registeredobjects.add( object );

}

}

所有我添加进 registeredobjects 中的object永远不会被gc回收,因为这里有个强引用保存在registeredobjects里,另一方面如果我把代码改为如下:

class registry {

private set registeredobjects = new hashset();

public void register(object object) {

registeredobjects.add( new weakreference(object) );

}

}

现在如果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 thefinalize() method.

翻译一下:

虚引用在实现一个对象被回收之前必须做清理操作是很有用的。有时候,他们比finalize()方法更灵活。

很明显的,虚引用可以用来做对象被回收之前的清理工作。


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/