本文将谈一下对
SoftReference(
软引用
)
、
WeakReference(
弱引用
)
和
PhantomRefrence(
虚引用
)
的理解
,
这三个类是对
heap
中
java
对象的应用
,
通过这个三个类可以和
gc
做简单的交互。
强引用:
除了上面提到的三个引用之外
,
还有一个引用
,
也就是最长用到的那就是强引用
.
例如:
Java
代码
1.Object o=new Object();
2.Object o1=o;
|
上面代码中第一句是在
heap
堆中创建新的
Object
对象通过
o
引用这个对象
,
第二句是通过
o
建立
o1
到
new Object()
这个
heap
堆中的对象的引用
,
这两个引用都是强引用
.
只要存在对
heap
中对象的引用
,
gc
就不会收集该对象
.
如果通过如下代码:
Java
代码
1.o=null;
2.o1=null;
|
如果显式地设置
o
和
o1
为
null
,
或超出范围
,
则
gc
认为该对象不存在引用
,这时
就可以收集它了。可以收集并不等于就一会被收集
,
什么时候收集这要取决于
gc
的算法
,
这要就带来很多不确定性。例如你就想指定一个对象,希望下次
gc
运行时把它收集了,那就没办法了,有了其他的三种引用就可以做到了。其他三种引用在不妨碍
gc
收集的情况下
,
可以做简单的交互
。
heap
中对象有强可及对象、软可及对象、弱可及对象、虚可及对象和不可到达对象。应用的强弱顺序是
强、软、弱、和虚
。对于对象是属于哪种可及的对象,由他的最强的引用决定。如
下
:
Java
代码
1.String abc=new String("abc"); //1
2.SoftReference<String> abcSoftRef=new SoftReference<String>(abc); //2
3.WeakReference<String> abcWeakRef = new WeakReference<String>(abc); //3
4.abc=null; //4
5.abcSoftRef.clear();//5
|
上面的代码中:
第一行在
heap
对中创建内容为
“abc”
的对象,并建立
abc
到该对象的强引用
,
该对象是强可及的。
第二行和第三行分别建立对
heap
中对象的软引用和弱引用
,
此时
heap
中的对象仍是强可及的
。
第四行之后
heap
中对象不再是强可及的,变成软可及的。同样第五行执行之后变成弱可及的。
SoftReference
(
软引用
)
软引用是主要用于内存敏感的高速缓存
。
在
jvm
报告内存不足之前会清除所有的软引用
,
这样以来
gc
就有可能收集软可及的对象
,
可能解决内存吃紧问题
,
避免内存溢出
。
什么时候会被收集取决于
gc
的算法和
gc
运行时可用内存的大小
。
当
gc
决定要收集软引用是执行以下过程
,
以上面的
abcSoftRef
为例
:
1
首先将
abcSoftRef
的
referent
设置为
null
,
不再引用
heap
中的
new String("abc")
对象
。
2
将
heap
中的
new String("abc")
对象设置为可结束的
(finalizable)
。
3
当
heap
中的
new String("abc")
对象的
finalize()
方法被运行而且该对象占用的内存被释放,
abcSoftRef
被添加到它的
ReferenceQueue
中
。
注
:
对
ReferenceQueue
软引用和弱引用可以有可无
,
但是虚引用必须有
,参
见:
Java
代码
Reference(T paramT, ReferenceQueue<? super T>paramReferenceQueue)
|
被
Soft Reference
指到的对象,即使没有任何
Direct Reference
,也不会被清除。一直要到
JVM
内存不足且
没有
Direct Reference
时才会清除,
SoftReference
是用来设计
object-cache
之用的。如此一来
SoftReference
不但可以把对象
cache
起来,也不会造成内存不足的错误
(
OutOfMemoryError
)。我觉得
Soft Reference
也适合拿来实作
pooling
的技巧。
A obj = new A();
SoftRefenrence sr = new SoftReference(obj);
引用
时
if(sr!=null){
obj = sr.get();
}else{
obj = new A();
sr = new SoftReference(obj);
}
|
弱引用
当
gc
碰到弱可及对象
,
并释放
abcWeakRef
的引用
,
收集该对象。但是
gc
可能需要对此运用才能找到该弱可及对象
。
通过如下代码可以了明了的看出它的作用
:
Java
代码
1.String abc=new String("abc");
2.WeakReference<String> abcWeakRef = new WeakReference<String>(abc);
3.abc=null;
4.System.out.println("before gc: "+abcWeakRef.get());
5.System.gc();
6.System.out.println("after gc: "+abcWeakRef.get());
|
运行结果
:
before gc: abc
after gc: null
gc
收集弱可及对象的执行过程和软可及一样
,
只是
gc
不会根据内存情况来决定是不是收集该对象
。
如果你希望能随
时
取得某
对
象的信息,但又不想影响此
对
象的垃圾收集,那
么
你
应该
用
Weak
Reference
来
记
住此
对
象,而不是用一般的
reference
。
A obj = new A();
WeakReference wr = new WeakReference(obj);
obj = null;
//
等待一段
时间,
obj
对象就会被垃圾回收
...
if (wr.get()==null) {
System.out.println("obj
已
经被清除了
");
} else {
System.out.println("obj
尚未被清除,其信息是
"+obj.toString());
}
...
}
|
在此例中,透过
get()
可以取得此
Reference
的所指到的对象,如果返回值为
null
的话,代表此对象已经被清除。
这类的技巧,在设计
Optimizer
或
Debugger
这类的程序时常会用到,因为这类程序需要取得某对象的信息,但是不可以
影响此对象的垃圾收集。
PhantomRefrence(
虚引用
)
虚顾名思义就是没有的意思
,
建立虚引用之后通过
get
方法返回结果始终为
null,
通过源代码你会发现
,
虚引用通向会把引用的对象写进
referent,
只是
get
方法返回结果为
null.
先看一下和
gc
交互的过程在说一下他的作用
.
1
不把
referent
设置为
null,
直接把
heap
中的
new String("abc")
对象设置为可结束的
(finalizable).
2
与软引用和弱引用不同
,
先把
PhantomRefrence
对象添加到它的
ReferenceQueue
中
.
然后在释放虚可及的对象
.
你会发现在收集
heap
中的
new String("abc")
对象之前
,
你就可以做一些其他的事情
.
通过以下代码可以了解他的作用
.
Java
代码
1.import java.lang.ref.PhantomReference;
2.import java.lang.ref.Reference;
3.import java.lang.ref.ReferenceQueue;
4.import java.lang.reflect.Field;
5.
6.public class Test {
7. public static boolean isRun = true;
8.
9. public static void main(String[] args) throws Exception {
10. String abc = new String("abc");
11. System.out.println(abc.getClass() + "@" + abc.hashCode());
12. final ReferenceQueue referenceQueue = new ReferenceQueue<String>();
13. new Thread() {
14. public void run() {
15. while (isRun) {
16. Object o = referenceQueue.poll();
17. if (o != null) {
18. try {
19. Field rereferent = Reference.class
20. .getDeclaredField("referent");
21. rereferent.setAccessible(true);
22. Object result = rereferent.get(o);
23. System.out.println("gc will collect:"
24. + result.getClass() + "@"
25. + result.hashCode());
26. } catch (Exception e) {
27.
28. e.printStackTrace();
29. }
30. }
31. }
32. }
33. }.start();
34. PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,
35. referenceQueue);
36. abc = null;
37. Thread.currentThread().sleep(3000);
38. System.gc();
39. Thread.currentThread().sleep(3000);
40. isRun = false;
41. }
42.
43.}
|
结果为
class java.lang.String@96354
gc will collect:class java.lang.String@96354