JVM的垃圾回收机制,就是清除无用对象所占用的空间,以及修复堆中碎片空间的机制。它根据对象的可达性来判断一个对象是否为“垃圾”。对象的可达性就是可触及性,它根据从根节点出发,是否能够到达对象,如果不能,就是不可触及,将回收。根节点的节点如常量池,方法中的本地变量等。可触及性分为四个程度:
1. 强可触及。根节点能够引用到该对象,如 String str = new String("123");就为创建了一个强克触及对象str,str指向堆内存创建的的String("123")对象。当程序员使用str=null时,便切断了str与new String(“123”)的引用,因此,new String("123")就失去了强可触及的状态,转而进入可恢复状态。
2. 可恢复。当JVM准备对该对象进行垃圾回收时,它会调用该类的finalize()方法。用户可以重写类的finalize方法(Object类的方法)。finalize()方法相当于是给对象再一次机会获得引用,若获得了引用,则恢复强可触及状态,否则,将进入不可达状态。
3. 不可达状态。当JVM发现一个对象是不可达时,它将回收该对象的内存。
Java引用对象和JVM的垃圾回收器密切相关。Java的引用对象在创建之后便一直维持对该对象的引用,直到该对象没有任何存在价值。Java的引用对象都继承自Reference抽象类,每一种实现都有它自身的独特之处。SoftReference可以用来避免OOM的问题,当系统的内存用尽时,将回收系统中的无用对象(存在时间最久的将被第一个回收)。WeakReference可以用来保护对象避免泄露,当WeakReference对象没有引用时,垃圾回收器将毫不犹豫地清理掉它。PhantomReference对象维持一个很弱的引用,它只是在对象准备回收时将它引用放入ReferenceQueue中,其实对象已经不存在,只是它提供了一种方法来避免finalize方法将它恢复的可能性。
使用SoftReference来构建缓存
创建Student类
public class Student {
private String id;
private String name;
private int classno;
public Student (String id , String name , int classno) {
this.id = id;
this.name = name;
this.classno = classno;
}
public String getID() {
return this.id;
}
public String toString() {
return this.id+" "+this.name+" "+this.classno;
}
}
创建SoftReference类的子类,使它符合使用要求(如start的时间,可用于在Map里面清除满足条件的Entry)
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
/**
*
* @author Administrator
*/
public class StudentRef extends SoftReference{
private long start;
public StudentRef(Student stu, ReferenceQueue q) {
super(stu, q);
this.start = System.currentTimeMillis();
System.out.println(start);
}
public long getStartTime() {
return this.start;
}
}
创建Cache的对象和方法
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class StudentCache {
private HashMap<String ,StudentRef> map;
private ReferenceQueue rq;
static private StudentCache sc;
private StudentCache() {
rq = new ReferenceQueue();
map = new HashMap<String,StudentRef>();
}
public static StudentCache getInstance() {
if(sc == null) {
return new StudentCache();
} else{
return StudentCache.sc;
}
}
/*如果满足条件的空的Reference,就清除*/
public void cleanCache() {
Reference r = null;
while((r=rq.poll())!=null) {
r.clear();
}
}
/*将对象加入Map中*/
public void cacheStudent (Student stu) {
if(map.containsKey(stu.getID())) {
return;
}
/*将引用注册进ReferenceQueue中,以便管理Reference对象的生存时间*/
StudentRef sturef = new StudentRef(stu,rq);
map.put(stu.getID(), sturef);
System.out.println("cached student "+stu.getID());
}
/*获取缓存中的数据,否则就创建缓存*/
public Student getStudentFromCache (String id) {
if(map.containsKey(id)) {
StudentRef sturef = map.get(id);
System.out.println("Student find!");
return (Student)sturef.get();
} else {
System.out.println("Fetching Student" + id + "from DB");
return null;
}
}
public void cleanAll () {
cleanCache();
map.clear();
System.gc();
System.runFinalization();
}
/*创建map方法的清除条件*/
public void cleanMap() {
long end = System.currentTimeMillis();
Iterator<Map.Entry<String,StudentRef>> it = map.entrySet().iterator();
while(it.hasNext()){
Map.Entry<String,StudentRef> entry = it.next();
StudentRef sturef = entry.getValue();
String id = entry.getKey();
if(end - sturef.getStartTime() > 1000) {
it.remove();
System.out.println("Remove "+id);
}
}
cleanCache();
}
public boolean isEmptyMap() {
return map.isEmpty();
}
}
当对象进入缓存后,就可以创建维护SoftReference的类,使用线程或定时器来维护。这里使用定时器来维护超时的HashMap。
import java.util.TimerTask;
/**
*
* @author Administrator
*/
public class CleanThread extends TimerTask {
private static StudentCache sc = StudentCache.getInstance();
@Override
public void run() {
System.out.println("Timer start!");
if(sc.isEmptyMap()) {
System.out.println("Map is Empty");
} else {
sc.cleanMap();
}
}
}
文中很多内容均来自对http://blog.csdn.net/coolwxb/article/details/7939246的理解。