- 浏览: 107526 次
- 性别:
- 来自: 福建厦门
文章分类
最新评论
-
yingzhixing:
收藏~
session.flush()的使用 -
strive708:
yugiohboy 写道xml文件: <bean id ...
hibernate+spring 的泛型dao接口和和实现类..以及配置 -
namelujl:
完美人生 www.okrs.cn
个人技术博客 www.kct ...
session.flush()的使用 -
yugiohboy:
xml文件: <bean id="testD ...
hibernate+spring 的泛型dao接口和和实现类..以及配置 -
silentJesse:
zhaolei415 写道看来兄弟比较认可李善友的这些话啊!! ...
李善友七律
Java 2 平台引入了 java.lang.ref 包,其中包括的类可以让您引用对象,而不将它们留在内存中。这些类还提供了与垃圾收集器(garbage collector)之间有限的交互。Peter Haggar 在本文中分析了 SoftReference、WeakReference 和 PhantomReference 类的功能和行为,并就这些类的使用给出了一些编程风格上的建议。
当在 Java 2 平台中首次引入 java.lang.ref 包(其中包含 SoftReference、WeakReference 和 PhantomReference 类)时,它的实用性显然被过分夸大了。它包含的类可能是有用的,但这些类具有的某些局限性会使它们显得不是很有吸引力,而且其应用程序也将特别局限于解决一类特定的问题。
垃圾收集概述
引用类的主要功能就是能够引用仍可以被垃圾收集器回收的对象。在引入引用类之前,我们只能使用强引用(strong reference)。举例来说,下面一行代码显示的就是强引用 obj:
Object obj = new Object();
obj 这个引用将引用堆中存储的一个对象。只要 obj 引用还存在,垃圾收集器就永远不会释放用来容纳该对象的存储空间。
当 obj 超出范围或被显式地指定为 null 时,垃圾收集器就认为没有对这个对象的其它引用,也就可以收集它了。然而您还需要注意一个重要的细节:仅凭对象可以被收集并不意味着垃圾收集器的一次指定运行就能够回收它。由于各种垃圾收集算法有所不同,某些算法会更频繁地分析生存期较短的对象,而不是较老、生存期较长的对象。因此,一个可供收集的对象可能永远也不会被回收。如果程序在垃圾收集器释放对象之前结束,这种情况就可能会出现。因此,概括地说,您永远无法保证可供收集的对象总是会被垃圾收集器收集。
这些信息对于您分析引用类是很重要的。由于垃圾收集有着特定的性质,所以引用类实际上可能没有您原来想像的那么有用,尽管如此,它们对于特定问题来说还是很有用的类。软引用(soft reference)、弱引用(weak reference)和虚引用(phantom reference)对象提供了三种不同的方式来在不妨碍收集的情况下引用堆对象。每种引用对象都有不同的行为,而且它们与垃圾收集器之间的交互也有所不同。此外,这几个新的引用类都表现出比典型的强引用“更弱”的引用形式。而且,内存中的一个对象可以被多个引用(可以是强引用、软引用、弱引用或虚引用)引用。在进一步往下讨论之前,让我们来看看一些术语:
强可及对象(strongly reachable):可以通过强引用访问的对象。
软可及对象(softly reachable):不是强可及对象,并且能够通过软引用访问的对象。
弱可及对象(weakly reachable):不是强可及对象也不是软可及对象,并且能够通过弱引用访问的对象。
虚可及对象(phantomly reachable):不是强可及对象、软可及对象,也不是弱可及对象,已经结束的,可以通过虚引用访问的对象。
清除:将引用对象的 referent 域设置为 null,并将引用类在堆中引用的对象声明为可结束的。
SoftReference 类
SoftReference 类的一个典型用途就是用于内存敏感的高速缓存。SoftReference 的原理是:在保持对对象的引用时保证在 JVM 报告内存不足情况之前将清除所有的软引用。关键之处在于,垃圾收集器在运行时可能会(也可能不会)释放软可及对象。对象是否被释放取决于垃圾收集器的算法以及垃圾收集器运行时可用的内存数量。
WeakReference 类
WeakReference 类的一个典型用途就是规范化映射(canonicalized mapping)。另外,对于那些生存期相对较长而且重新创建的开销也不高的对象来说,弱引用也比较有用。关键之处在于,垃圾收集器运行时如果碰到了弱可及对象,将释放 WeakReference 引用的对象。然而,请注意,垃圾收集器可能要运行多次才能找到并释放弱可及对象。
PhantomReference 类
PhantomReference 类只能用于跟踪对被引用对象即将进行的收集。同样,它还能用于执行 pre-mortem 清除操作。PhantomReference 必须与 ReferenceQueue 类一起使用。需要 ReferenceQueue 是因为它能够充当通知机制。当垃圾收集器确定了某个对象是虚可及对象时,PhantomReference 对象就被放在它的 ReferenceQueue 上。将 PhantomReference 对象放在 ReferenceQueue 上也就是一个通知,表明 PhantomReference 对象引用的对象已经结束,可供收集了。这使您能够刚好在对象占用的内存被回收之前采取行动。
垃圾收集器和引用交互
垃圾收集器每次运行时都可以随意地释放不再是强可及的对象占用的内存。如果垃圾收集器发现了软可及对象,就会出现下列情况:
SoftReference 对象的 referent 域被设置为 null,从而使该对象不再引用 heap 对象。
SoftReference 引用过的 heap 对象被声明为 finalizable。
当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放,SoftReference 对象就被添加到它的 ReferenceQueue(如果后者存在的话)。
如果垃圾收集器发现了弱可及对象,就会出现下列情况:
WeakReference 对象的 referent 域被设置为 null,从而使该对象不再引用 heap 对象。
WeakReference 引用过的 heap 对象被声明为 finalizable。
当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放时,WeakReference 对象就被添加到它的 ReferenceQueue(如果后者存在的话)。
如果垃圾收集器发现了虚可及对象,就会出现下列情况:
PhantomReference 引用过的 heap 对象被声明为 finalizable。
与软引用和弱引用有所不同,PhantomReference 在堆对象被释放之前就被添加到它的 ReferenceQueue。(请记住,所有的 PhantomReference 对象都必须用经过关联的 ReferenceQueue 来创建。)这使您能够在堆对象被回收之前采取行动。
请考虑清单 1 中的代码。
清单 1. 使用 WeakReference 及 ReferenceQueue 的示例代码
//Create a strong reference to an object
MyObject obj = new MyObject(); //1
//Create a reference queue
ReferenceQueue rq = new ReferenceQueue(); //2
//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq); //3
行 //1 创建 MyObject 对象,而行 //2 则创建 ReferenceQueue 对象。行 //3 创建引用其引用对象 MyObject 的 WeakReference 对象,还创建它的 ReferenceQueue。请注意,每个对象引用(obj、rq 及 wr)都是强引用。要利用这些引用类,您必须取消对 MyObject 对象的强引用,方法是将 obj 设置为 null。前面说过,如果不这样做,对象 MyObject 永远都不会被回收,引用类的任何优点都会被削弱。
每个引用类都有一个 get() 方法,而 ReferenceQueue 类有一个 poll() 方法。get() 方法返回对被引用对象的引用。在 PhantomReference 上调用 get() 总是会返回 null。这是因为 PhantomReference 只用于跟踪收集。poll() 方法返回已被添加到队列中的引用对象,如果队列中没有任何对象,它就返回 null。因此,执行清单 1 之后再调用 get() 和 poll() 的结果可能是:
wr.get(); //returns reference to MyObject
rq.poll(); //returns null
现在我们假定垃圾收集器开始运行。由于 MyObject 对象没有被释放,所以 get() 和 poll() 方法将返回同样的值;obj 仍然保持对该对象进行强引用。实际上,对象布局还是没有改变,和图 1 所示的差不多。然而,请考虑下面的代码:
obj = null;
System.gc(); //run the collector
现在,调用 get() 和 poll() 将产生与前面不同的结果:
wr.get(); //returns null
rq.poll(); //returns a reference to the WeakReference object
这种情况表明,MyObject 对象(对它的引用原来是由 WeakReference 对象进行的)不再可用。这意味着垃圾收集器释放了 MyObject 占用的内存,从而使 WeakReference 对象可以被放在它的 ReferenceQueue 上。这样,您就可以知道当 WeakReference 或 SoftReference 类的 get() 方法返回 null 时,就有一个对象被声明为 finalizable,而且可能(不过不一定)被收集。只有当 heap 对象完全结束而且其内存被回收后,WeakReference 或 SoftReference 才会被放到与其关联的 ReferenceQueue 上。清单 2 显示了一个完整的可运行程序,它展示了这些原理中的一部分。这段代码本身就颇具说明性,它含有很多注释和打印语句,可以帮助您理解。
清单 2. 展示引用类原理的完整程序
import java.lang.ref.*;
class MyObject
{
protected void finalize() throws Throwable
{
System.out.println("In finalize method for this object: " +
this);
}
}
class ReferenceUsage
{
public static void main(String args[])
{
hold();
release();
}
public static void hold()
{
System.out.println("Example of incorrectly holding a strong " +
"reference");
//Create an object
MyObject obj = new MyObject();
System.out.println("object is " + obj);
//Create a reference queue
ReferenceQueue rq = new ReferenceQueue();
//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq);
System.out.println("The weak reference is " + wr);
//Check to see if it´s on the ref queue yet
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
System.out.println("Calling GC");
System.gc();
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
}
public static void release()
{
System.out.println("");
System.out.println("Example of correctly releasing a strong " +
"reference");
//Create an object
MyObject obj = new MyObject();
System.out.println("object is " + obj);
//Create a reference queue
ReferenceQueue rq = new ReferenceQueue();
//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq);
System.out.println("The weak reference is " + wr);
//Check to see if it´s on the ref queue yet
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
System.out.println("Set the obj reference to null and call GC");
obj = null;
System.gc();
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
}
}
用途和风格
这些类背后的原理就是避免在应用程序执行期间将对象留在内存中。相反,您以软引用、弱引用或虚引用的方式引用对象,这样垃圾收集器就能够随意地释放对象。当您希望尽可能减小应用程序在其生命周期中使用的堆内存大小时,这种用途就很有好处。您必须记住,要使用这些类,您就不能保留对对象的强引用。如果您这么做了,那就会浪费这些类所提供的任何好处。
另外,您必须使用正确的编程风格以检查收集器在使用对象之前是否已经回收了它,如果已经回收了,您首先必须重新创建该对象。这个过程可以用不同的编程风格来完成。选择错误的风格会导致出问题。请考虑清单 3 中从 WeakReference 检索被引用对象的代码风格:
清单 3. 检索被引用对象的风格
obj = wr.get();
if (obj == null)
{
wr = new WeakReference(recreateIt()); //1
obj = wr.get(); //2
}
//code that works with obj
研究了这段代码之后,请看看清单 4 中从 WeakReference 检索被引用对象的另一种代码风格:
清单 4. 检索被引用对象的另一种风格
obj = wr.get();
if (obj == null)
{
obj = recreateIt(); //1
wr = new WeakReference(obj); //2
}
//code that works with obj
请比较这两种风格,看看您能否确定哪种风格一定可行,哪一种不一定可行。清单 3 中体现出的风格不一定在所有情况下都可行,但清单 4 的风格就可以。清单 3 中的风格不够好的原因在于,if 块的主体结束之后 obj 不一定是非空值。请考虑一下,如果垃圾收集器在清单 3 的行 //1 之后但在行 //2 执行之前运行会怎样。recreateIt() 方法将重新创建该对象,但它会被 WeakReference 引用,而不是强引用。因此,如果收集器在行 //2 在重新创建的对象上施加一个强引用之前运行,对象就会丢失,wr.get() 则返回 null。
清单 4 不会出现这种问题,因为行 //1 重新创建了对象并为其指定了一个强引用。因此,如果垃圾收集器在该行之后(但在行 //2 之前)运行,该对象就不会被回收。然后,行 //2 将创建对 obj 的 WeakReference。在使用这个 if 块之后的 obj 之后,您应该将 obj 设置为 null,从而让垃圾收集器能够回收这个对象以充分利用弱引用。清单 5 显示了一个完整的程序,它将展示刚才我们描述的风格之间的差异。(要运行该程序,其运行目录中必须有一个“temp.fil”文件。
清单 5. 展示正确的和不正确的编程风格的完整程序。
import java.io.*;
import java.lang.ref.*;
class ReferenceIdiom
{
public static void main(String args[]) throws FileNotFoundException
{
broken();
correct();
}
public static FileReader recreateIt() throws FileNotFoundException
{
return new FileReader("temp.fil");
}
public static void broken() throws FileNotFoundException
{
System.out.println("Executing method broken");
FileReader obj = recreateIt();
WeakReference wr = new WeakReference(obj);
System.out.println("wr refers to object " + wr.get());
System.out.println("Now, clear the reference and run GC");
//Clear the strong reference, then run GC to collect obj.
obj = null;
System.gc();
System.out.println("wr refers to object " + wr.get());
//Now see if obj was collected and recreate it if it was.
obj = (FileReader)wr.get();
if (obj == null)
{
System.out.println("Now, recreate the object and wrap it
in a WeakReference");
wr = new WeakReference(recreateIt());
System.gc(); //FileReader object is NOT pinned...there is no
//strong reference to it. Therefore, the next
//line can return null.
obj = (FileReader)wr.get();
}
System.out.println("wr refers to object " + wr.get());
}
public static void correct() throws FileNotFoundException
{
System.out.println("");
System.out.println("Executing method correct");
FileReader obj = recreateIt();
WeakReference wr = new WeakReference(obj);
System.out.println("wr refers to object " + wr.get());
System.out.println("Now, clear the reference and run GC");
//Clear the strong reference, then run GC to collect obj
obj = null;
System.gc();
System.out.println("wr refers to object " + wr.get());
//Now see if obj was collected and recreate it if it was.
obj = (FileReader)wr.get();
if (obj == null)
{
System.out.println("Now, recreate the object and wrap it
in a WeakReference");
obj = recreateIt();
System.gc(); //FileReader is pinned, this will not affect
//anything.
wr = new WeakReference(obj);
}
System.out.println("wr refers to object " + wr.get());
}
}
总结
如果使用得当,引用类还是很有用的。然而,由于它们所依赖的垃圾收集器行为有时候无法预知,所以其实用性就会受到影响。能否有效地使用它们还取决于是否应用了正确的编程风格;关键在于您要理解这些类是如何实现的以及如何对它们进行编程。
=================================================================================
Java 对象的状态有:
* 已创建(created)
* 强可达(strong reachable)
* 不可见(invisible)
* 不可达(unreachable)
* 已收集(collected)
* 终化(finalized)
* 已回收(deallocated)
Java对象生命周期的状态转换: {image:img=objectstatus.jpg|width=400} 引用对象
三种新的引用类型:
* 软引用(soft reference)
* 弱引用(weak reference)
* 幻引用(phantom reference)
强可达(Strong Reachable)
定义: ~An object is strong reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strong reachable by the thread that created it.~
处于强可达状态的对象, 在任何情况下都不会被回收掉. 软可达(Softly Reachable)
定义:~An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference.~
含义是:当对象不处于强可达状态, 并且可以通过软引用进行访问时, 即处于软可达状态.
当程序申请内存的时候, 垃圾收集器会判断是否开始回收处于软可达状态的对象, 如果决定回收某个对象, 那么垃圾收集器会清除所有指向该对象的软引用, 如果任何处于其它软可达状态的对象可以通过强引用访问该对象, 那么指向这些对象的软引用也会被清除掉. 垃圾收集器在决定哪些软可达状态的对象被收集时, 采用"最久未被使用"原则, 或称"最不常使用"原则. 垃圾收集器也保证在OutOfMemeryError产生以前, 所有的软引用都被清除.
* 产生和使用一个软引用
// createSoftReference sr = new SoftReference(new SomeObject());// getSomeObject o = (SomeObject) sf.get();// create in a reference queue;ReferenceQueue queue = new ReferenceQueue();SoftReference sr = new SoftReference(new SomeObject(), queue);
弱可达(Weakly Reachable)
定义:~An Object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference.~
垃圾收集器会一次清除所有弱引用. 幻可达(Phantomly Reachable)
定义:~An object is phantomly reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.~
幻引用不能直接创建. 必须通过向引用队列等级的途径来创建:
ReferenceQueue queue = new ReferenceQueue();PhantomReference pr = new PhantomReference (new SomeObject(), queue);
你不可能从幻引用再次得到对象, pr.get()永远返回null. 另外, 必须调用Reference.clear()手工清除幻引用. All About ReferenceObjects No InterWiki reference defined in properties for Wiki called '[http'!)]
Reference Objects No InterWiki reference defined in properties for Wiki called '[http'!)]
Reference Objects and Garbage Collection No InterWiki reference defined in properties for Wiki called '[http'!)]
\[Jike Thread\?Soft, Weak, and Phantom References|http://www-124.ibm.com/pipermail/jikesrvm-core/2003-May/000365.html]
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1492810
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
public class Testone {
public static void main(String args[]){
A a=new A();
//a.test();
//SoftReference sr = new SoftReference(a);
ReferenceQueue<A> rq = new ReferenceQueue<A>();
WeakReference<A> wr = new WeakReference<A>(a, rq);
a = null;
System.out.println(wr.get());
System.out.println(rq.poll());
System.gc();
System.runFinalization();
System.out.println(wr.get());
System.out.println(rq.poll());
if (wr != null) {
a = (A)wr.get();
System.out.println("asdasdas");
a.test();
}
else{
a = new A();
System.out.println("123123");
a.test();
a = null;
wr = new WeakReference<A>(a);
}
}
}
class A{
void test(){
System.out.println("A.test()");
}
}
一個ReferenceQueue的例子(軟引用)
查看結果,你就會清楚
如果我們把a = null;注釋掉,那麼軟引用就沒有發揮出作用
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
public class Testone {
public static void main(String args[]){
A a=new A();
//a.test();
//SoftReference sr = new SoftReference(a);
SoftReference<A> sr = new SoftReference<A>(a);
a = null;
System.out.println(sr.get());
ArrayList<Object> o=new ArrayList<Object>(15462000);
//System.gc();
//System.runFinalization();
System.out.println(sr.get());
if (sr != null) {
a = (A)sr.get();
System.out.println("asdasdas");
a.test();
}
else{
a = new A();
System.out.println("123123");
a.test();
a = null;
sr = new SoftReference<A>(a);
}
}
}
class A{
void test(){
System.out.println("A.test()");
}
}
運行結果:
A@35ce36
null
asdasdas
Exception in thread "main" java.lang.NullPointerException
at Testone.main(Testone.java:22)
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/leboy/archive/2009/09/06/4524202.aspx
当在 Java 2 平台中首次引入 java.lang.ref 包(其中包含 SoftReference、WeakReference 和 PhantomReference 类)时,它的实用性显然被过分夸大了。它包含的类可能是有用的,但这些类具有的某些局限性会使它们显得不是很有吸引力,而且其应用程序也将特别局限于解决一类特定的问题。
垃圾收集概述
引用类的主要功能就是能够引用仍可以被垃圾收集器回收的对象。在引入引用类之前,我们只能使用强引用(strong reference)。举例来说,下面一行代码显示的就是强引用 obj:
Object obj = new Object();
obj 这个引用将引用堆中存储的一个对象。只要 obj 引用还存在,垃圾收集器就永远不会释放用来容纳该对象的存储空间。
当 obj 超出范围或被显式地指定为 null 时,垃圾收集器就认为没有对这个对象的其它引用,也就可以收集它了。然而您还需要注意一个重要的细节:仅凭对象可以被收集并不意味着垃圾收集器的一次指定运行就能够回收它。由于各种垃圾收集算法有所不同,某些算法会更频繁地分析生存期较短的对象,而不是较老、生存期较长的对象。因此,一个可供收集的对象可能永远也不会被回收。如果程序在垃圾收集器释放对象之前结束,这种情况就可能会出现。因此,概括地说,您永远无法保证可供收集的对象总是会被垃圾收集器收集。
这些信息对于您分析引用类是很重要的。由于垃圾收集有着特定的性质,所以引用类实际上可能没有您原来想像的那么有用,尽管如此,它们对于特定问题来说还是很有用的类。软引用(soft reference)、弱引用(weak reference)和虚引用(phantom reference)对象提供了三种不同的方式来在不妨碍收集的情况下引用堆对象。每种引用对象都有不同的行为,而且它们与垃圾收集器之间的交互也有所不同。此外,这几个新的引用类都表现出比典型的强引用“更弱”的引用形式。而且,内存中的一个对象可以被多个引用(可以是强引用、软引用、弱引用或虚引用)引用。在进一步往下讨论之前,让我们来看看一些术语:
强可及对象(strongly reachable):可以通过强引用访问的对象。
软可及对象(softly reachable):不是强可及对象,并且能够通过软引用访问的对象。
弱可及对象(weakly reachable):不是强可及对象也不是软可及对象,并且能够通过弱引用访问的对象。
虚可及对象(phantomly reachable):不是强可及对象、软可及对象,也不是弱可及对象,已经结束的,可以通过虚引用访问的对象。
清除:将引用对象的 referent 域设置为 null,并将引用类在堆中引用的对象声明为可结束的。
SoftReference 类
SoftReference 类的一个典型用途就是用于内存敏感的高速缓存。SoftReference 的原理是:在保持对对象的引用时保证在 JVM 报告内存不足情况之前将清除所有的软引用。关键之处在于,垃圾收集器在运行时可能会(也可能不会)释放软可及对象。对象是否被释放取决于垃圾收集器的算法以及垃圾收集器运行时可用的内存数量。
WeakReference 类
WeakReference 类的一个典型用途就是规范化映射(canonicalized mapping)。另外,对于那些生存期相对较长而且重新创建的开销也不高的对象来说,弱引用也比较有用。关键之处在于,垃圾收集器运行时如果碰到了弱可及对象,将释放 WeakReference 引用的对象。然而,请注意,垃圾收集器可能要运行多次才能找到并释放弱可及对象。
PhantomReference 类
PhantomReference 类只能用于跟踪对被引用对象即将进行的收集。同样,它还能用于执行 pre-mortem 清除操作。PhantomReference 必须与 ReferenceQueue 类一起使用。需要 ReferenceQueue 是因为它能够充当通知机制。当垃圾收集器确定了某个对象是虚可及对象时,PhantomReference 对象就被放在它的 ReferenceQueue 上。将 PhantomReference 对象放在 ReferenceQueue 上也就是一个通知,表明 PhantomReference 对象引用的对象已经结束,可供收集了。这使您能够刚好在对象占用的内存被回收之前采取行动。
垃圾收集器和引用交互
垃圾收集器每次运行时都可以随意地释放不再是强可及的对象占用的内存。如果垃圾收集器发现了软可及对象,就会出现下列情况:
SoftReference 对象的 referent 域被设置为 null,从而使该对象不再引用 heap 对象。
SoftReference 引用过的 heap 对象被声明为 finalizable。
当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放,SoftReference 对象就被添加到它的 ReferenceQueue(如果后者存在的话)。
如果垃圾收集器发现了弱可及对象,就会出现下列情况:
WeakReference 对象的 referent 域被设置为 null,从而使该对象不再引用 heap 对象。
WeakReference 引用过的 heap 对象被声明为 finalizable。
当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放时,WeakReference 对象就被添加到它的 ReferenceQueue(如果后者存在的话)。
如果垃圾收集器发现了虚可及对象,就会出现下列情况:
PhantomReference 引用过的 heap 对象被声明为 finalizable。
与软引用和弱引用有所不同,PhantomReference 在堆对象被释放之前就被添加到它的 ReferenceQueue。(请记住,所有的 PhantomReference 对象都必须用经过关联的 ReferenceQueue 来创建。)这使您能够在堆对象被回收之前采取行动。
请考虑清单 1 中的代码。
清单 1. 使用 WeakReference 及 ReferenceQueue 的示例代码
//Create a strong reference to an object
MyObject obj = new MyObject(); //1
//Create a reference queue
ReferenceQueue rq = new ReferenceQueue(); //2
//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq); //3
行 //1 创建 MyObject 对象,而行 //2 则创建 ReferenceQueue 对象。行 //3 创建引用其引用对象 MyObject 的 WeakReference 对象,还创建它的 ReferenceQueue。请注意,每个对象引用(obj、rq 及 wr)都是强引用。要利用这些引用类,您必须取消对 MyObject 对象的强引用,方法是将 obj 设置为 null。前面说过,如果不这样做,对象 MyObject 永远都不会被回收,引用类的任何优点都会被削弱。
每个引用类都有一个 get() 方法,而 ReferenceQueue 类有一个 poll() 方法。get() 方法返回对被引用对象的引用。在 PhantomReference 上调用 get() 总是会返回 null。这是因为 PhantomReference 只用于跟踪收集。poll() 方法返回已被添加到队列中的引用对象,如果队列中没有任何对象,它就返回 null。因此,执行清单 1 之后再调用 get() 和 poll() 的结果可能是:
wr.get(); //returns reference to MyObject
rq.poll(); //returns null
现在我们假定垃圾收集器开始运行。由于 MyObject 对象没有被释放,所以 get() 和 poll() 方法将返回同样的值;obj 仍然保持对该对象进行强引用。实际上,对象布局还是没有改变,和图 1 所示的差不多。然而,请考虑下面的代码:
obj = null;
System.gc(); //run the collector
现在,调用 get() 和 poll() 将产生与前面不同的结果:
wr.get(); //returns null
rq.poll(); //returns a reference to the WeakReference object
这种情况表明,MyObject 对象(对它的引用原来是由 WeakReference 对象进行的)不再可用。这意味着垃圾收集器释放了 MyObject 占用的内存,从而使 WeakReference 对象可以被放在它的 ReferenceQueue 上。这样,您就可以知道当 WeakReference 或 SoftReference 类的 get() 方法返回 null 时,就有一个对象被声明为 finalizable,而且可能(不过不一定)被收集。只有当 heap 对象完全结束而且其内存被回收后,WeakReference 或 SoftReference 才会被放到与其关联的 ReferenceQueue 上。清单 2 显示了一个完整的可运行程序,它展示了这些原理中的一部分。这段代码本身就颇具说明性,它含有很多注释和打印语句,可以帮助您理解。
清单 2. 展示引用类原理的完整程序
import java.lang.ref.*;
class MyObject
{
protected void finalize() throws Throwable
{
System.out.println("In finalize method for this object: " +
this);
}
}
class ReferenceUsage
{
public static void main(String args[])
{
hold();
release();
}
public static void hold()
{
System.out.println("Example of incorrectly holding a strong " +
"reference");
//Create an object
MyObject obj = new MyObject();
System.out.println("object is " + obj);
//Create a reference queue
ReferenceQueue rq = new ReferenceQueue();
//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq);
System.out.println("The weak reference is " + wr);
//Check to see if it´s on the ref queue yet
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
System.out.println("Calling GC");
System.gc();
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
}
public static void release()
{
System.out.println("");
System.out.println("Example of correctly releasing a strong " +
"reference");
//Create an object
MyObject obj = new MyObject();
System.out.println("object is " + obj);
//Create a reference queue
ReferenceQueue rq = new ReferenceQueue();
//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq);
System.out.println("The weak reference is " + wr);
//Check to see if it´s on the ref queue yet
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
System.out.println("Set the obj reference to null and call GC");
obj = null;
System.gc();
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
}
}
用途和风格
这些类背后的原理就是避免在应用程序执行期间将对象留在内存中。相反,您以软引用、弱引用或虚引用的方式引用对象,这样垃圾收集器就能够随意地释放对象。当您希望尽可能减小应用程序在其生命周期中使用的堆内存大小时,这种用途就很有好处。您必须记住,要使用这些类,您就不能保留对对象的强引用。如果您这么做了,那就会浪费这些类所提供的任何好处。
另外,您必须使用正确的编程风格以检查收集器在使用对象之前是否已经回收了它,如果已经回收了,您首先必须重新创建该对象。这个过程可以用不同的编程风格来完成。选择错误的风格会导致出问题。请考虑清单 3 中从 WeakReference 检索被引用对象的代码风格:
清单 3. 检索被引用对象的风格
obj = wr.get();
if (obj == null)
{
wr = new WeakReference(recreateIt()); //1
obj = wr.get(); //2
}
//code that works with obj
研究了这段代码之后,请看看清单 4 中从 WeakReference 检索被引用对象的另一种代码风格:
清单 4. 检索被引用对象的另一种风格
obj = wr.get();
if (obj == null)
{
obj = recreateIt(); //1
wr = new WeakReference(obj); //2
}
//code that works with obj
请比较这两种风格,看看您能否确定哪种风格一定可行,哪一种不一定可行。清单 3 中体现出的风格不一定在所有情况下都可行,但清单 4 的风格就可以。清单 3 中的风格不够好的原因在于,if 块的主体结束之后 obj 不一定是非空值。请考虑一下,如果垃圾收集器在清单 3 的行 //1 之后但在行 //2 执行之前运行会怎样。recreateIt() 方法将重新创建该对象,但它会被 WeakReference 引用,而不是强引用。因此,如果收集器在行 //2 在重新创建的对象上施加一个强引用之前运行,对象就会丢失,wr.get() 则返回 null。
清单 4 不会出现这种问题,因为行 //1 重新创建了对象并为其指定了一个强引用。因此,如果垃圾收集器在该行之后(但在行 //2 之前)运行,该对象就不会被回收。然后,行 //2 将创建对 obj 的 WeakReference。在使用这个 if 块之后的 obj 之后,您应该将 obj 设置为 null,从而让垃圾收集器能够回收这个对象以充分利用弱引用。清单 5 显示了一个完整的程序,它将展示刚才我们描述的风格之间的差异。(要运行该程序,其运行目录中必须有一个“temp.fil”文件。
清单 5. 展示正确的和不正确的编程风格的完整程序。
import java.io.*;
import java.lang.ref.*;
class ReferenceIdiom
{
public static void main(String args[]) throws FileNotFoundException
{
broken();
correct();
}
public static FileReader recreateIt() throws FileNotFoundException
{
return new FileReader("temp.fil");
}
public static void broken() throws FileNotFoundException
{
System.out.println("Executing method broken");
FileReader obj = recreateIt();
WeakReference wr = new WeakReference(obj);
System.out.println("wr refers to object " + wr.get());
System.out.println("Now, clear the reference and run GC");
//Clear the strong reference, then run GC to collect obj.
obj = null;
System.gc();
System.out.println("wr refers to object " + wr.get());
//Now see if obj was collected and recreate it if it was.
obj = (FileReader)wr.get();
if (obj == null)
{
System.out.println("Now, recreate the object and wrap it
in a WeakReference");
wr = new WeakReference(recreateIt());
System.gc(); //FileReader object is NOT pinned...there is no
//strong reference to it. Therefore, the next
//line can return null.
obj = (FileReader)wr.get();
}
System.out.println("wr refers to object " + wr.get());
}
public static void correct() throws FileNotFoundException
{
System.out.println("");
System.out.println("Executing method correct");
FileReader obj = recreateIt();
WeakReference wr = new WeakReference(obj);
System.out.println("wr refers to object " + wr.get());
System.out.println("Now, clear the reference and run GC");
//Clear the strong reference, then run GC to collect obj
obj = null;
System.gc();
System.out.println("wr refers to object " + wr.get());
//Now see if obj was collected and recreate it if it was.
obj = (FileReader)wr.get();
if (obj == null)
{
System.out.println("Now, recreate the object and wrap it
in a WeakReference");
obj = recreateIt();
System.gc(); //FileReader is pinned, this will not affect
//anything.
wr = new WeakReference(obj);
}
System.out.println("wr refers to object " + wr.get());
}
}
总结
如果使用得当,引用类还是很有用的。然而,由于它们所依赖的垃圾收集器行为有时候无法预知,所以其实用性就会受到影响。能否有效地使用它们还取决于是否应用了正确的编程风格;关键在于您要理解这些类是如何实现的以及如何对它们进行编程。
=================================================================================
Java 对象的状态有:
* 已创建(created)
* 强可达(strong reachable)
* 不可见(invisible)
* 不可达(unreachable)
* 已收集(collected)
* 终化(finalized)
* 已回收(deallocated)
Java对象生命周期的状态转换: {image:img=objectstatus.jpg|width=400} 引用对象
三种新的引用类型:
* 软引用(soft reference)
* 弱引用(weak reference)
* 幻引用(phantom reference)
强可达(Strong Reachable)
定义: ~An object is strong reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strong reachable by the thread that created it.~
处于强可达状态的对象, 在任何情况下都不会被回收掉. 软可达(Softly Reachable)
定义:~An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference.~
含义是:当对象不处于强可达状态, 并且可以通过软引用进行访问时, 即处于软可达状态.
当程序申请内存的时候, 垃圾收集器会判断是否开始回收处于软可达状态的对象, 如果决定回收某个对象, 那么垃圾收集器会清除所有指向该对象的软引用, 如果任何处于其它软可达状态的对象可以通过强引用访问该对象, 那么指向这些对象的软引用也会被清除掉. 垃圾收集器在决定哪些软可达状态的对象被收集时, 采用"最久未被使用"原则, 或称"最不常使用"原则. 垃圾收集器也保证在OutOfMemeryError产生以前, 所有的软引用都被清除.
* 产生和使用一个软引用
// createSoftReference sr = new SoftReference(new SomeObject());// getSomeObject o = (SomeObject) sf.get();// create in a reference queue;ReferenceQueue queue = new ReferenceQueue();SoftReference sr = new SoftReference(new SomeObject(), queue);
弱可达(Weakly Reachable)
定义:~An Object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference.~
垃圾收集器会一次清除所有弱引用. 幻可达(Phantomly Reachable)
定义:~An object is phantomly reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.~
幻引用不能直接创建. 必须通过向引用队列等级的途径来创建:
ReferenceQueue queue = new ReferenceQueue();PhantomReference pr = new PhantomReference (new SomeObject(), queue);
你不可能从幻引用再次得到对象, pr.get()永远返回null. 另外, 必须调用Reference.clear()手工清除幻引用. All About ReferenceObjects No InterWiki reference defined in properties for Wiki called '[http'!)]
Reference Objects No InterWiki reference defined in properties for Wiki called '[http'!)]
Reference Objects and Garbage Collection No InterWiki reference defined in properties for Wiki called '[http'!)]
\[Jike Thread\?Soft, Weak, and Phantom References|http://www-124.ibm.com/pipermail/jikesrvm-core/2003-May/000365.html]
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1492810
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
public class Testone {
public static void main(String args[]){
A a=new A();
//a.test();
//SoftReference sr = new SoftReference(a);
ReferenceQueue<A> rq = new ReferenceQueue<A>();
WeakReference<A> wr = new WeakReference<A>(a, rq);
a = null;
System.out.println(wr.get());
System.out.println(rq.poll());
System.gc();
System.runFinalization();
System.out.println(wr.get());
System.out.println(rq.poll());
if (wr != null) {
a = (A)wr.get();
System.out.println("asdasdas");
a.test();
}
else{
a = new A();
System.out.println("123123");
a.test();
a = null;
wr = new WeakReference<A>(a);
}
}
}
class A{
void test(){
System.out.println("A.test()");
}
}
一個ReferenceQueue的例子(軟引用)
查看結果,你就會清楚
如果我們把a = null;注釋掉,那麼軟引用就沒有發揮出作用
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
public class Testone {
public static void main(String args[]){
A a=new A();
//a.test();
//SoftReference sr = new SoftReference(a);
SoftReference<A> sr = new SoftReference<A>(a);
a = null;
System.out.println(sr.get());
ArrayList<Object> o=new ArrayList<Object>(15462000);
//System.gc();
//System.runFinalization();
System.out.println(sr.get());
if (sr != null) {
a = (A)sr.get();
System.out.println("asdasdas");
a.test();
}
else{
a = new A();
System.out.println("123123");
a.test();
a = null;
sr = new SoftReference<A>(a);
}
}
}
class A{
void test(){
System.out.println("A.test()");
}
}
運行結果:
A@35ce36
null
asdasdas
Exception in thread "main" java.lang.NullPointerException
at Testone.main(Testone.java:22)
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/leboy/archive/2009/09/06/4524202.aspx
发表评论
-
Class 和 class,反射,泛型
2011-02-22 17:12 11591.class 是java里面声明一 ... -
java反射机制
2011-02-22 17:07 710一、反射的功能四个功能 1.在运行时判断任意一个对象所属的类 ... -
对泛型之不能协变(convariant)的理解,以及不能协变导致的问题
2011-02-21 10:51 21071.何为协变 假设有一个接口,以及一个他的实现类 如下: 接口 ... -
枚举的理解
2011-02-18 11:09 8821.为什么引入枚举 2.枚举的地位:枚举和类、接口有一样的地 ... -
对强引用,弱引用,软引用的定义
2011-02-18 09:44 1370背景: 在JDK1.2以前的 ... -
泛型的理解
2011-02-17 11:57 9321.为什么引入泛型 Java语 ... -
java对象本质
2011-02-16 23:05 919对象本质上是一种命名技术,即将一组相关的数据和函数放在一起,起 ... -
java中float f=1.1为什么不合法
2011-02-15 16:30 2022因为Java里带有小数点的数默认是double类型,所以1.1 ... -
java中的强类型和弱类型
2011-02-14 23:08 5571首先弄清四个概念: 1.静态类型定义语言 一种在 ...
相关推荐
在 Java 中,引用可以分为四类:强引用、软引用、弱引用和虚引用(也称为精灵引用)。弱引用是其中的一种,它们允许垃圾回收器在某些情况下回收对象,而不是像强引用那样坚持对象的存在。 弱引用的工作原理是,当...
时间局部性的开发是利用在高速缓冲存储器中保留最近使用的指令及数据,并且定义缓冲存储的优先级。 习题: 1.1、图1.3中的理想机器还有两条I/O指令: 0011 = 从I/O中载入AC 0111 = 把AC保存到I/O中 在这种情况下...
在实际应用中,目标程序需要链接器进行进一步处理,以解决外部引用和库函数的问题,生成最终的可执行文件。 总的来说,编译原理涵盖了诸如文法分析、词法分析、语法分析、语义分析等多个方面,是理解计算机系统如何...
文法分为四类:0型、1型、2型和3型,分别对应于无限制文法、上下文有关文法、上下文无关文法和正规文法。 **1. 最左推导与最右推导** 最左推导和最右推导是两种基本的推导方式。最左推导是指在每一步推导中,总是...
使用VB实现单链表操作时,可以创建一个节点类(Node Class),该类包含两个字段:一个是存储数据的Data字段,另一个是引用下一个节点的Next字段。Next字段在VB中通常是通过对象引用来实现的,可以指向另一个同类型的...
SQL的工作原理是,用户通过SQL向数据库管理系统(DBMS)发送请求,DBMS解析并执行这些请求,然后将结果返回给用户。 SQL的核心功能可以分为四类:数据查询语言(DQL)、数据定义语言(DDL)、数据操作语言(DML)和...
引用标准方面,文中列出了中国国家标准GB1207-97《电压互感器》、GB1208-97《电流互感器》、2BY096-82《精密电压互感器技术条件》、2BY097-82《精密电流互感器技术条件》以及GB311.1-83《高压输变电设备的绝缘配合》...
控制原理上,通过检测库区及卸氨区内的氨气浓度,若达到报警浓度,PLC控制系统会启动相应的排风和喷淋系统以及紧急切断装置。 3. 氨浓度检测报警仪的作用:氨浓度检测报警仪负责实时监测液氨库区和卸氨区域内的氨气...
精度通常基于引用误差来定义,引用误差是绝对误差与量程的比值。真值在实际操作中无法直接获得,通常用约定真值和相对真值近似。绝对误差是测量值与理想值之间的差距,而相对误差则表示这个差距相对于测量值的比例。...
【基础】java基本数据类型(四类八种) 15 Java自动类型转换 16 数据类型自动提升(注意以下讨论的是二元操作符) 16 【基础】switch支持的类型 17 【基础】当一个对象被当作参数传递到一个方法后,此方法可改变这个...
当使用`require()`函数引用这些模块时,Node.js会通过`Module.prototype._require()`函数查找和加载它们。这个过程首先会尝试从缓存中加载模块,如果未找到,则按照预定的路径规则(如当前目录、`node_modules`目录...
参考文献和注释在学术写作中有明确区别,参考文献是引用的文献书目,集中列于文末,而注释是对正文内容的解释或补充,用数字加圆圈标注。餐厅设计应考虑简单、便捷、卫生和舒适,饭厅与厨房通常需要毗邻或接近。 ...
指示仪表是通过机械偏转角来显示被测量大小的直读式仪表,如安装式仪表和便携式仪表,它们根据工作原理分为磁电系、电磁系、电动系和感应系等。比较仪表则通过被测量与标准量的比较来确定测量值,如直流电桥和电位差...
6.1.4 击键和字符 6.2 击键消息 6.2.1 系统键击和非系统键击 6.2.2 虚拟键代码 6.2.3 1param信息 6.2.4 转义状态 6.2.5 使用击键消息 6.2.6 为SYSMETS加上键盘处理功能 6.3 字符消息 6.3.1 四类字符消息 6.3.2 消息...
7. **控制及状态寄存器**:这是执行指令必不可少的四类寄存器,包括程序计数器(PC)、指令寄存器(IR)、内存地址寄存器(MAR)和内存数据寄存器(MDR)。它们各自承担着特定的任务,如PC负责存储下一条要执行的...
- **解析**: Java程序主要分为四类:类(Class)、Applet、Application 和 Servlet。其中,Application是独立运行的应用程序,而Applet是嵌入网页中的小型应用程序。Servlet则是一种服务器端的应用组件。 **2. 编译...
9. **参数传递**:主要有传值和传引用两种方式,前者是复制实参的值给形参,后者是让形参直接引用实参的内存地址。 10. **抽象数据类型**:ADT是一种逻辑上的数据类型,它定义了数据的集合和对这些数据的操作,但不...