对象的四种引用级别

从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活地控制对象的生命周期。这四种级别分别是: [b]强引用[/b], [b]软引用[/b],[b]弱引用[/b]和[b]虚引用[/b]。

[b]1. 强引用[/b]
这是使用最普遍的引用。如果一个对象具有强引用,垃圾回收器就不会回收它。在内存不足的情况下,JVM宁愿抛出
[color=red]OutOfMemoryError[/color]错误,使程序异常终止,也不会强行回收具有强引用的对象所占用的空间!

[b]2. 软引用(SoftReference)[/b]
如果一个对象[b]只[/b]具有软引用, 那么只要内存空间足够,垃圾回收器就不会回收它,但如果内存空间不足了,就会坚定不移地回收这些具有软引用的对象所占用的空间。
因此,软引用可以用来实现 [color=blue]内存敏感的高速缓存[/color]。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,JVM就会把这个[b]软引用[/b](是软引用本身,而不是之前具有软引用的对象)加入到与其关联的引用队列中。
---------------------
如果垃圾收集器发现了软引用对象,就会出现一下情况:
SoftReference对象的referent域被设置为null,使它不再引用堆对象。
SoftReference应用的堆对象被声明为 finalizable。
当堆对象的finalize()方法被执行且占用的内存被释放,SoftReference对象就被添加到它的ReferenceQueue中(如果后者存在的话)。


[b]3.弱引用(WeakReference)[/b]
如果一个对象[b]只[/b]具有弱引用,它就拥有了比软引用更短暂的生命周期。
在垃圾回收线程扫描它所管理的内存区域的过程中,一旦发现只具有弱引用的对象,不管当前内存空间是否足够,都会回收它! 但由于垃圾回收线程是一个优先级很低的线程,因此不一定很快就能发现那些只具有弱引用的对象。
弱引用也可以和一个引用队列联合使用,当弱引用的对象被垃圾回收,JVM就会把这个弱引用加入到与之关联的引用队列中。
弱引用的一个典型用途就是规范化映射(canonicalized mapping).另外,对于那些生存期相对较长,而且重新创建的开销也不高的对象来说,弱引用比较有用。
---------------------
如果垃圾收集器发现了弱引用对象,就会出现一下情况:
WeakReference对象的referent域被设置为null,使它不再引用堆对象。
WeakReference应用的堆对象被声明为 finalizable。
当堆对象的finalize()方法被执行且占用的内存被释放,WeakReference对象就被添加到它的ReferenceQueue中(如果后者存在的话)。


[b]4.虚引用(PhantomReference)[/b]
虚引用与前三种引用类型不同,它不会影响对象的生命周期,同时必须和引用队列联合使用。如果一个对象仅持有虚引用,那么这个对象就跟没有任何引用一样,随时可能被垃圾回收。
虚引用主要用来跟踪对象被垃圾回收的事件。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收,并在垃圾回收前采取必要的行动。
---------------------
如果垃圾收集器发现了虚引用对象,就会出现一下情况:
PhantomReference应用的堆对象被声明为 finalizable。
与软、弱引用不同,PhantomReference在堆对象被释放前就被添加到它的ReferenceQueue。这使您能够在堆对象被回收之前采取及时而有效的行动。


java.lang.ref包中提供了三个类:SoftReference类,WeakReference类和PhantomReference类,分别代表 软引用,弱引用,虚引用。 ReferenceQueue类表示引用队列,同前面三种 引用类 联合使用,以跟踪JVM垃圾回收的活动。


[code]//创建一个强引用
String str = new String("hello");
//创建引用队列,<String>为泛型标记,表明队列中存放String对象的引用
ReferenceQueue<String> rq = new ReferenceQueue<String>();
//创建一个弱引用,它引用前面的“hello”对象,并且与rq应用队列关联
WeakReference<String> wf = new WeakReference<String>(str,rq);[/code]

执行上述代码后,内存中[b]引用[/b]与[b]对象[/b]的关系如下图所示:
[img]http://www.javathinker.org/java/ref_1.gif[/img]

在图中,带实线的箭头表示强引用,带虚线的箭头表示弱引用。可以看到堆空间里面的
“hello”对象具有一个叫做str的强引用,还被WeakReference对象弱引用,因此
“hello”对象不会被垃圾回收。


下面的代码中,把强引用“hello”对象的str变量设置为null,然后再通过WeakReference的get()方法获得“hello”对象的弱引用:

[code]String str = new String("hello");
ReferenceQueue<String> rq = new ReferenceQueue<String>();
WeakReference<String> wf = new WeakReference<String>(str,rq);
str = null; //消除了“hello”对象的强引用
String str1 = wf.get();//如果“hello”对象在取消强引用str后还没被回收,则再次具有强引用str1
Reference<? extends String> ref = rq.poll();//如果“hello”对象没有被回收,rq.poll()返回null[/code]


执行完上面第四行代码后,“hello”对象只具有弱引用了,因此有被垃圾回收的可能。
假如它还没有来得及被回收(垃圾回收线程优先级比较低,恰好发生在4,5行之间的概率不是很高),接下来在第5行执行wf.get()方法会返回“hello”对象的引用,并使“hello”对象被str1强引用。接下来在第6行执行rq.poll()方法会返回
null,因为此时引用队列中没有任何引用。ReferenceQueue的poll()方法用于返回队列中的引用,如果没有则返回null。

[code]String str = new String("hello");
ReferenceQueue<String> rq = new ReferenceQueue<String>();
WeakReference<String> wf = new WeakReference<String>(str,rq);
str = null;
System.gc();//连续两次催促垃圾回收器工作,提高只有弱引用的“hello”对象被回收的可能性
System.gc();
String str1 = wf.get();//如果“hello”已经被回收,str1为null
Reference<? extends String> ref = rq.poll();[/code]
在上述代码中,执行完第四行后,“hello”对象仅仅具有弱引用。接着两次调用
System.gc()方法,催促垃圾回收器工作,从而提高“hello”对象被回收的可能性。
假如“hello”对象被回收,那么WeakReference对象的引用被加入到ReferenceQueue中,接下啦wf.get()方法返回null,并且rq.poll()方法返回WeakReference对象的引用。下图展示了执行完后,内存中引用与对象的关系:
[img]http://www.javathinker.org/java/ref_3.gif[/img]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值