Thinking in java P554
持有引用
如果想继续持有对某个对象的引用,希望以后能够反问到该对象,
但是也希望能够允许垃圾回收器是否它,这是就应该使用Reference
对象。这样,可以继续使用改对象,而再内存消耗完时允许是否它。
以Reference对象作为你和普通引用的媒介,另外,一定不能有
普通的引用指向那个兑现g.zheyang就能达到上述目的。
(普通的引用指没有经Reference对象包装过的引用)。
如果垃圾回收器发现某个兑现沟通过普通引用是可获得的,该
对象就不会被释放。
SoftReference, WeakReference 和 PhantomReference由强到若,
对应不同级别的"可获得性".Softreference用以是想内存
敏感的高速缓存。Weak reference是为实现个"规范映射"
而设计的,它部妨碍垃圾回收器回收映射的键或值。
规范映射中对象的实力可以在程序的多处被同时使用,
以节省存储空间。Phantomreference用以调度回收前
的清理工作,比Java终止机制更灵活。
class VeryBig {
private static final int SIZE = 10000;
private long[] la = new long[SIZE];
private String ident;
public VeryBig(String id){
ident = id;
}
@Override
public String toString() {
return ident;
}
@Override
protected void finalize() throws Throwable {
System.out.println("Finalizing "+ident);
}
}
public class References{
private static ReferenceQueue<VeryBig> rq =
new ReferenceQueue<VeryBig>();
public static void checkQueue(){
Reference<? extends VeryBig> inq = rq.poll();
if(inq != null)
System.out.println("In Queue: "+inq.get());
}
public static void main(String[] args) {
int size = 10;
if(args.length > 0)
size = new Integer(args[0]);
LinkedList<SoftReference<VeryBig>> sa =
new LinkedList<SoftReference<VeryBig>>();
for(int i=0; i<size; i++){
sa.add(new SoftReference<VeryBig>(
new VeryBig("Soft "+ i), rq)
);
System.out.println("Just created: "+sa.getLast());
checkQueue();
}
LinkedList<WeakReference<VeryBig>> wa =
new LinkedList<WeakReference<VeryBig>>();
for(int i=0; i<size; i++){
wa.add(new WeakReference<VeryBig>(
new VeryBig("Weak "+ i), rq)
);
System.out.println("Just created: "+wa.getLast());
checkQueue();
}
SoftReference<VeryBig> s =
new SoftReference<VeryBig>(new VeryBig("Soft"));
WeakReference<VeryBig> w =
new WeakReference<VeryBig>(new VeryBig("Weak"));
System.gc();
LinkedList<PhantomReference<VeryBig>> pa =
new LinkedList<PhantomReference<VeryBig>>();
for(int i=0; i<size; i++){
pa.add(new PhantomReference<VeryBig>(
new VeryBig("Phantom "+ i), rq)
);
System.out.println("Just created: "+pa.getLast());
checkQueue();
}
}
}
结果
Just created: java.lang.ref.WeakReference@1d5550d
Just created: java.lang.ref.WeakReference@c2ea3f
Just created: java.lang.ref.WeakReference@a0dcd9
Just created: java.lang.ref.WeakReference@1034bb5
Just created: java.lang.ref.WeakReference@f9f9d8
Finalizing Weak 0
Finalizing Weak
Finalizing Weak 8
Finalizing Weak 7
Finalizing Weak 6
Finalizing Weak 5
Finalizing Weak 4
Finalizing Weak 3
Finalizing Weak 2
Finalizing Weak 1
Finalizing Weak 9
Just created: java.lang.ref.PhantomReference@112f614
In Queue: null
Just created: java.lang.ref.PhantomReference@1d9dc39
In Queue: null
Just created: java.lang.ref.PhantomReference@93dcd
In Queue: null
Just created: java.lang.ref.PhantomReference@b89838
In Queue: null
Just created: java.lang.ref.PhantomReference@111a3ac
In Queue: null
Just created: java.lang.ref.PhantomReference@dd20f6
In Queue: null
Just created: java.lang.ref.PhantomReference@723d7c
In Queue: null
Just created: java.lang.ref.PhantomReference@1d1acd3
In Queue: null
Just created: java.lang.ref.PhantomReference@8814e9
In Queue: null
Just created: java.lang.ref.PhantomReference@1503a3
In Queue: null
尽管还要通过Reference对象访问那些对象(使用get()取得实际的对象引用),
但是还是被垃圾回收器回收了。
可以看到,REferenceQueue总是生成一个包含null对象的Reference.
容器中WeakHashMap,用来保存WeakReference。每个值只保存一份实例
以节省存储空间,查值,则在映射中查询现有对象,然后使用它。
映射可将值作为其初始化一部分,不过通常是在需要的时候才生成值。
对于向WeakHashMap添加键和值的操作,没有什么特殊要求,映射会
自动使用WeakReference包装他们。允许清理元素的触发条件是,
不需要这个键。
class Element{
private String ident;
public Element(String id){
ident = id;
}
public String toString(){
return ident;
}
public int hashCode(){
return ident.hashCode();
}
public boolean equals(Object r){
return r instanceof Element &&
ident.equals(((Element)r).ident);
}
protected void finalize(){
System.out.println("Finalizing "+
getClass().getSimpleName()+" "+ident);
}
}
class Key extends Element{
public Key(String id){
super(id);
}
}
class Value extends Element{
public Value(String id){
super(id);
}
}
public class CanonicalMapping {
public static void main(String[] args) {
int size = 1000;
if(args.length > 0)
size = new Integer(args[0]);
Key[] keys = new Key[size];
WeakHashMap<Key, Value> map =
new WeakHashMap<Key, Value>();
for(int i=0; i<size; i++){
Key k = new Key(Integer.toString(i));
Value v = new Value(Integer.toString(i));
if(i%3==0)
keys[i] = k;
map.put(k, v);
}
System.gc();
}
}
结果:
zing Key 209
Finalizing Key 208
Finalizing Key 206
Finalizing Key 205
Finalizing Key 203
Finalizing Key 202
Finalizing Key 200
Finalizing Key 199
Finalizing Key 197
Finalizing Key 196
Finalizing Key 194
Finalizing Key 193
Finalizing Key 191
Finalizing Key 190
Finalizing Key 188
...
可以看到垃圾回收期每隔三个键就跳过一个,因为指向那个键的普通引用被存如了Keys数组,
所以偶那些对象不能被垃圾回收器回收。