您的位置:首页 > Web前端

java基础之java.lang.ref.Reference

2014-06-05 00:00 393 查看

Reference

java.lang.ref类库主要作用在于当内存不足时,能够提醒gc,将一些使用ref定义的变量释放掉以缓解内存不足的压力。java.lang.ref.Reference有三种不同的子类,SoftReference,WeakReference以及PhantomReference。它们分成了三种不同的级别,gc会在不同的情况下一一释放它们引用对象的空间。

SoftReference

当我们希望对象的引用仍驻留在内存里面,直到内存出现不足时,gc会释放由SoftReference引用对象所占的内存空间。所以SoftReference可以用作Cache的实现。

package io.github.klink;

// containers/References.java
// Demonstrates Reference objects
import java.lang.ref.*;
import java.util.*;

class VeryBig {
private static final int SIZE = 10000;
private long[] la = new long[SIZE];
private String ident;
public VeryBig(String id) { ident = id; }
public String toString() { return ident; }
protected void finalize() {
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;

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();
}

System.gc();

try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

for(int i = 0; i < size; i++) {
checkQueue();
}

输出为:

Just created: java.lang.ref.SoftReference@5e1077
Just created: java.lang.ref.SoftReference@18b3364
Just created: java.lang.ref.SoftReference@1db05b2
Just created: java.lang.ref.SoftReference@530cf2
Just created: java.lang.ref.SoftReference@76fba0
Just created: java.lang.ref.SoftReference@181ed9e
Just created: java.lang.ref.SoftReference@1175422
Just created: java.lang.ref.SoftReference@949f69
Just created: java.lang.ref.SoftReference@16dadf9
Just created: java.lang.ref.SoftReference@1b8d6f7

WeakReference

WeakReference并不会影响其引用对象的生命周期。换句话说,如果该对象只被WeakReference引用的话,它仍然会被gc回收。但是在gc回收之前,WeakReference会普通的引用没有区别,都可以访问引用对象的成员。WeakReference可用于:一个对象可能会有若干的引用,当我们不清楚这些引用是否仍在的时候,可以通过WeakReference引用该对象,如果该对象仍在内存中的话,WeakReference就可以获取对象的值,如果不在的话,WeakReference将会为Null。

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();
}

System.gc();

try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

for(int i = 0; i < size; i++) {
checkQueue();
}

输出结果为:

Just created: java.lang.ref.WeakReference@18b3364
Just created: java.lang.ref.WeakReference@1db05b2
Just created: java.lang.ref.WeakReference@530cf2
Just created: java.lang.ref.WeakReference@76fba0
Just created: java.lang.ref.WeakReference@181ed9e
Just created: java.lang.ref.WeakReference@1175422
Just created: java.lang.ref.WeakReference@949f69
Just created: java.lang.ref.WeakReference@16dadf9
Just created: java.lang.ref.WeakReference@1b8d6f7
Just created: java.lang.ref.WeakReference@290fbc
Finalizing Weak 9
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 0
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null

PhantomReference

PhantomReference与WeakReference一样,不会影响其引用对象的生命周期。PhantomReference与前两个Reference不同的是,它并不会引用对象,(这就是为什么使用PhantomReference的get()方法总是返回null的原因)。我们从它的构造函数可以看到,它有两个参数其中一个是ReferenceQueue,在gc回收时,会将PhantomReference引用的对象插入到ReferenceQueue中。

但是在实际的代码执行过程中,并没有插入到ReferenceQueue,这点让我比较困惑。

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();
}

System.gc();

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i = 0; i < size; i++) {
checkQueue();
}

输出结果为:

Just created: java.lang.ref.PhantomReference@5e1077
Just created: java.lang.ref.PhantomReference@18b3364
Just created: java.lang.ref.PhantomReference@1db05b2
Just created: java.lang.ref.PhantomReference@530cf2
Just created: java.lang.ref.PhantomReference@76fba0
Just created: java.lang.ref.PhantomReference@181ed9e
Just created: java.lang.ref.PhantomReference@1175422
Just created: java.lang.ref.PhantomReference@949f69
Just created: java.lang.ref.PhantomReference@16dadf9
Just created: java.lang.ref.PhantomReference@1b8d6f7
Finalizing Phantom 9
Finalizing Phantom 8
Finalizing Phantom 7
Finalizing Phantom 6
Finalizing Phantom 5
Finalizing Phantom 4
Finalizing Phantom 3
Finalizing Phantom 2
Finalizing Phantom 1
Finalizing Phantom 0

ReferenceQueue

每一个Reference的实现都会有一个构造函数需要ReferenceQueue作为参数。当Reference的子类绑定一个ReferenceQueue时,Reference所指向的对象一旦被gc回收,gc会再回收之前将对象插入到ReferenceQueue中。

WeakHashMap

WeakHashMap是基于WeakReference实现的一个Map。其特点是,WeakHashMap中的Key如果没有被任何对象引用的话,那么当gc回收垃圾的时候,这些未被引用的Key对应的记录会被删除。

package io.github.klink;

import java.util.*;

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;
// Or, choose size via the command line:

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; // Save as "real" references
map.put(k, v);
}
System.gc();
}
}

输出结果为:

Finalizing Key 98
Finalizing Key 625
Finalizing Key 683
Finalizing Key 733
Finalizing Key 779
Finalizing Key 811
Finalizing Key 856
Finalizing Key 901
Finalizing Key 944
Finalizing Key 977
Finalizing Key 998
Finalizing Key 997
Finalizing Key 995
Finalizing Key 994
Finalizing Key 992
Finalizing Key 991
Finalizing Key 989
Finalizing Key 988
Finalizing Key 986
Finalizing Key 985
Finalizing Key 983
Finalizing Key 982
Finalizing Key 980
Finalizing Key 979
Finalizing Key 976
Finalizing Key 974
Finalizing Key 973
Finalizing Key 971
Finalizing Key 970
Finalizing Key 968
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息