`
leonzhx
  • 浏览: 793702 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

WeakReference 与 PhantomReference 加入ReferenceQueue时机的疑惑

    博客分类:
  • Java
阅读更多

阅读了 Guidelines for using the Java 2 reference classes  与 Understanding Weak References  之后,发现两篇文章关于 WeakReference 和 PhantomReference 何时被加入到 ReferenceQueue有些出入。也就是说到底是在引用的对象没有强引用时还是在引用的对象真正被回收时。于是写了如下程序进行验证:

package mypackage;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

class TestObj {
	
	//定义三种Reference用于保存指向本对象的Reference,从而在finalize中检验他们的get()值
	private SoftReference sr = null;
	private WeakReference wr = null;
	private PhantomReference pr = null;
	
	//定义ReferenceQueue用于在finalize中检验指向本对象的reference是否被加入了这个Queue
	private static ReferenceQueue rq = null;

	public static void setQueue(ReferenceQueue referenceQueue) {
		rq = referenceQueue;
	}

	public void setSr(SoftReference sr) {
		this.sr = sr;
	}

	public void setWr(WeakReference wr) {
		this.wr = wr;
	}

	public void setPr(PhantomReference pr) {
		this.pr = pr;
	}

	public void finalize() {
		
		//检验指向本对象的Reference的get()值
		if (null != sr)
			System.out.println("Soft Reference refers to " + sr.get()
					+ " in finalize().");
		if (null != wr)
			System.out.println("Weak Reference refers to " + wr.get()
					+ " in finalize().");
		if (null != pr)
			System.out.println("Phantom Reference refers to " + pr.get()
					+ " in finalize().");

		
		//验证是不是在对象finalize()的时候他的soft reference已经被加入至Queue中
		Reference r = rq.poll();

		while (null != r) {
			System.out.println(r.getClass().getName()
					+ " is added in the queue in finalize().");
			r = rq.poll();
		}

	}
}

public class Test {

	public static void main(String[] args) {
		{
           //用于传给三种Reference的强引用
			TestObj softObj = new TestObj();
			TestObj weakObj = new TestObj();
			TestObj phantomObj = new TestObj();

			ReferenceQueue rq = new ReferenceQueue();

		   //三种Reference指向三个不同的对象
			SoftReference sr = new SoftReference(softObj, rq);
			WeakReference wr = new WeakReference(weakObj, rq);
			PhantomReference pr = new PhantomReference(phantomObj, rq);
           
		   //将Reference传回给对应的对象
			softObj.setSr(sr);
			weakObj.setWr(wr);
			phantomObj.setPr(pr);
			
			//将ReferenceQueue传回给对象类
			TestObj.setQueue(rq);
            
			//删除强引用
			softObj = null;
			weakObj = null;
			phantomObj = null;
			System.gc();
			
			Reference r = null;

			// 为了确保对象被GC回收
			//******************************************
			
			while (null == r)
			{
				System.gc();
				r = rq.poll();
			}
			//******************************************

			while (null != r) {
				System.out.println(r.getClass().getName()
						+ " is added in the queue out of finalize().");
				r = rq.poll();
			}

		}

	}

}

 

但发现程序输出的结果是:

 

Phantom Reference refers to null in finalize().
Weak Reference refers to null in finalize().
Soft Reference refers to null in finalize().

 

这就有点让我纳闷了,到底是这些Reference没被加入Queue中呢还是内存中的对象没了被真正回收呢? 以/********包围起来的语句是我后来加上去的,是为了确保对象确实被回收,但发现这样的话程序就死循环了。

 

请高手解疑:)

1
0
分享到:
评论
5 楼 leonzhx 2010-10-01  
JDK 1.6的ReferenceQueue.enqueue

boolean enqueue (Reference reference) {
	if (reference instanceof sun.misc.Cleaner) {
		reference.dequeue();
		((sun.misc.Cleaner)reference).clean();
		return true;
	}
	synchronized(this) {
		if(!empty && head == tail) {
			/* Queue is full - grow */
			int newQueueSize = (int)(references.length * 1.10);
			Reference newQueue[] = new Reference[newQueueSize];
			System.arraycopy(references, head, newQueue, 0, references.length - head);
			if(tail > 0) {
				System.arraycopy(references, 0, newQueue, references.length - head, tail);
			}
			head = 0;
			tail = references.length;
			references = newQueue;
		}
		references[tail++] = reference;
		if(tail == references.length) {
			tail = 0;
		}
		empty = false;
		notifyAll();
	}
	return true;
}
4 楼 leonzhx 2010-10-01  
你说的ReferenceQueue贴出来是什么意思?
现在程序出的只是各种Reference的get()方法的输出。程序执行时就在
引用
while (null == r)  
            {  
                System.gc();  
                r = rq.poll();  
            }  

死循环了,说明ReferenceQueue里一直没东西。
3 楼 mercyblitz 2010-10-01  
leonzhx 写道
谢谢mercyblitz的指教。我更新了一下代码并加了一些注释。
首先,你贴的是ReferenceQueue的enqueue的代码吧?我这里JDK1.6好像不是长这样的。。。
其次,就是因为System.gc()靠不住,所以我加了/*********包起来的那段,但程序还是死循环。。。




没有错,你的ReferenceQueue贴出来呢!
2 楼 leonzhx 2010-10-01  
谢谢mercyblitz的指教。我更新了一下代码并加了一些注释。
首先,你贴的是ReferenceQueue的enqueue的代码吧?我这里JDK1.6好像不是长这样的。。。
其次,就是因为System.gc()靠不住,所以我加了/*********包起来的那段,但程序还是死循环。。。


1 楼 mercyblitz 2010-10-01  
代码没有怎么看明白!

一般而言,Strong、Soft、Weak和Phantom描述的是对象可达性,只有完全不可达时,对象才会真正的回收。

对象回收至少经过两个周期,前finalize期,可达性从Strong->Soft->Weak。

下个周期-finalize期,这个时候对象编程了,final reference(finalize可达性),在JDK中提供一个非public的类 - java.lang.ref.FinalReference。

SUN JDK源码中有提示:
 
boolean enqueue(Reference<? extends T> r) {	/* Called only by Reference class */
	synchronized (r) {
	    if (r.queue == ENQUEUED) return false;
	    synchronized (lock) {
		r.queue = ENQUEUED;
		r.next = (head == null) ? r : head;
		head = r;
		queueLength++;
                if (r instanceof FinalReference) { //
                    sun.misc.VM.addFinalRefCount(1); //添加final reference 计数
                }
		lock.notifyAll();
		return true;
	    }
	}
}


对象被finalized之后,对象的可达性为finalize。

而Phantom在finalize之后,这就是为什么引用对象总是返回null。

因此,SUN JDK里有5个可达性,按照强弱排列:Strong、Soft、Weak、Finalize和Phantom。

注意除了Phantom以外,ReferenceQueue都会返回被入队的引用。

另外,System.gc();  是靠不住的。所以,多次运行结果会不多。


发表评论

文章已被作者锁定,不允许评论。

相关推荐

    深入探讨 java-lang-ref 包.docx

    在垃圾回收器对弱引用对象进行回收的时机。弱引用所指向的对象,无论内存状况如何,只要没有其他强引用存在,垃圾回收器在下一次执行GC时就会回收它,而不会等待内存压力达到某个阈值。弱引用通常用于创建临时性或者...

    详解Java对象的强、软、弱和虚引用+ReferenceQueue

    软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。 三、弱引用(WeakReference) 弱引用与软引用的区别...

    Java引用总结--StrongReference、SoftReference、WeakReference、PhantomRef

    软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。 弱引用(WeakReference)弱引用与软引用的区别在于:只...

    软弱虚引用_转

    它还可以与引用队列(ReferenceQueue)联合使用,一旦被引用的对象被回收,软引用本身会被加入到引用队列中。 弱引用(WeakReference)与软引用类似,但具有更短的生命周期。当垃圾回收器扫描内存区域时,不论当前...

    Java 引用1

    软引用通常与`ReferenceQueue`配合使用,当对象被回收时,软引用会被加入到队列中。例如: ```java SoftReference&lt;String&gt; softRef = new SoftReference(new String("hello"), referenceQueue); ``` 3. **弱引用...

    Java对象的引用.pdf

    这些引用类型通过`java.lang.ref`包中的`SoftReference`、`WeakReference`和`PhantomReference`类实现,而`ReferenceQueue`类用于与这三种引用类型一起工作,记录引用对象被回收的信息。 以下是一个简单的例子展示...

    Java中弱引用软引用虚引用及强引用的区别Java开发Ja

    - 示例:`PhantomReference&lt;String&gt; phantomRef = new PhantomReference(new String("PhantomReference Test"), new ReferenceQueue());` 理解这四种引用类型有助于开发者在设计和实现复杂系统时,更好地控制对象...

    Java的四种引用

    PhantomReference&lt;String&gt; phantomRef = new PhantomReference(str, queue); if (queue.poll() == null) { System.out.println("phantom reference is still valid."); } else { System.out.println("phantom ...

    Java中的软引用弱引用和虚引用.docx

    // 通过ReferenceQueue检查虚引用是否被加入队列 System.out.println(queue.poll()); // 输出 "abc" 的虚引用 } } ``` #### 六、总结 通过对软引用、弱引用和虚引用的介绍与示例代码,我们可以看到这三种引用...

    java 常见的四种引用

    当垃圾回收器准备回收一个对象时,如果发现该对象有虚引用,那么在回收对象之前,会将这个虚引用加入到与之关联的引用队列中。这样,开发者可以通过检查引用队列来确定对象是否已经被垃圾回收。 示例代码: ```java...

    Java对象的强、软、弱和虚引用1

    软引用会与引用队列(ReferenceQueue)配合使用,当软引用的对象被回收时,会被加入到引用队列。 3. **弱引用(WeakReference)**: 相比于软引用,弱引用的对象拥有更短的生命周期。在垃圾回收器扫描时,无论内存...

    java 引用相关文档

    - 示例:`PhantomReference&lt;String&gt; phantomRef = new PhantomReference(new String("Hello"), new ReferenceQueue());` 这些引用类型的使用需要根据具体需求来选择。例如,软引用常用于缓存策略,以保持一定数量...

    如何解决Java的循环引用问题

    3. 使用虚引用(PhantomReference): 虚引用是最弱的一种引用类型,它不保证在任何时候都能获取到被引用的对象,只能在对象被回收后通过队列得知。虚引用主要用于跟踪对象被回收的状态,而不是延缓对象的回收。 4....

    Java 7之基础 - 强引用、弱引用、软引用、虚引用1

    - **例子**:` PhantomReference&lt;Object&gt; phantomRef = new PhantomReference(new Object(), new ReferenceQueue());` - **特点**:虚引用主要用来跟踪对象被垃圾收集的状态,通常不用于内存管理。 了解和正确...

    浅谈Java中的四种引用方式的区别

    PhantomReference&lt;String&gt; pr = new PhantomReference(new String("hello"), new ReferenceQueue()); ``` 通过理解这四种引用,开发者可以在设计程序时更好地控制内存使用,避免内存泄漏,并在必要时优雅地处理...

    Java中的强软弱虚引用

    当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象之前,把这个虚引用加入到与之关联的队列中。程序可以通过检查这个队列,获取到虚引用的信息,并采取相应的行动。 #### 六、总结 综上所述,...

    Java功底之Reference

    1. 创建引用子类的实例,如`SoftReference`, `WeakReference`, 或 `PhantomReference`。 2. 将引用实例与目标对象关联。 3. 使用`get()`方法检查引用是否仍然有效。对于软引用和弱引用,如果对象被回收,`get()`将...

    Java中几个Reference常见的作用详解

    - 使用`ReferenceQueue`可以监控引用对象的状态变化,特别是对于`WeakReference`和`PhantomReference`。 - 避免过度依赖`SoftReference`作为缓存策略,因为它可能导致程序在内存紧张时不稳定。 - `PhantomReference`...

    Java中管理资源的引用队列相关原理解析

    WeakReference&lt;T&gt; weakRef = new WeakReference(referent, referenceQueue); ``` 这里的`referent`是目标对象,`referenceQueue`则是引用队列。当垃圾回收器确定`referent`对象达到特定的可达性状态(如弱可达或虚...

Global site tag (gtag.js) - Google Analytics