首页 > 代码库 > Java -强引用&弱引用
Java -强引用&弱引用
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题.
使用强引用的一个例子。
图像缓存问题,图像缓存应该阻止我们重新载入图像,所以图像缓存保存有内存中已有的所有图像的引用,如果使用通常的强引用,强引用本身会使得图像一直存留在内存中,这样就使得程序员像上面一样,必须自己决定什么时候移除缓存中的引用,这样对象才能被垃圾回收机制回收。
当你想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候你就是用弱引用。这个引用不会影响gc对对象的回收。
ReferenceQueue queue = new ReferenceQueue ();PhantomReference pr = new PhantomReference (object, queue);
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
二、对象的可达性判断
在很多时候,一个对象并不是从根集直接引用的,而是一个对象被其他对象引用,甚至同时被几个对象所引用,从而构成一个以根集为顶的树形结构。如图2所示
在这个树形的引用链中,箭头的方向代表了引用的方向,所指向的对象是被引用对象。由图可以看出,从根集到一个对象可以由很多条路径。比如到达对象5的路径就有①-⑤,③-⑦两条路径。由此带来了一个问题,那就是某个对象的可及性如何判断:
MyObject aRef = new MyObject();SoftReference aSoftRef=new SoftReference(aRef);
此时,对于这个MyObject对象,有两个引用路径,一个是来自SoftReference对象的软引用,一个来自变量aReference的强引用,所以这个MyObject对象是强可及对象。
ReferenceQueue queue = new ReferenceQueue();SoftReference ref=new SoftReference(aMyObject, queue);
那么当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当我们调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。
SoftReference ref = null;while ((ref = (EmployeeRef) q.poll()) != null) { // 清除ref}
package com.volshell.demo;import java.lang.ref.ReferenceQueue;import java.lang.ref.SoftReference;import java.util.Hashtable;/** * @author volshell * 以软引用的方式引用并存储对象(以对象为参数创建软引用) * 在从软引用中获取对象 .get() * 如果沒用从引用中获取对象,在这个时候再去创建一个对象,并将其建立引用。 * 如果在创建引用对象的时候创建了引用队列,使用get() = null 的时候,说明该对象已经被回收,那么这个软引用也没有存在的价值了 * 所以需要删除,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。 */public class EmployeeCache { static private EmployeeCache cache;// 一个Cache实例 private Hashtable<String, EmployeeRef> employeeRefs;// 用于Cache内容的存储 private ReferenceQueue<Employee> q;// 垃圾Reference的队列 // 继承SoftReference,使得每一个实例都具有可识别的标识。 // 并且该标识与其在HashMap内的key相同。 private class EmployeeRef extends SoftReference<Employee> { private String _key = ""; public EmployeeRef(Employee em, ReferenceQueue<Employee> q) { super(em, q); _key = em.getId(); } } // 构建一个缓存器实例 private EmployeeCache() { employeeRefs = new Hashtable<String, EmployeeRef>(); q = new ReferenceQueue<Employee>(); } // 取得缓存器实例 public static EmployeeCache getInstance() { if (cache == null) { cache = new EmployeeCache(); } return cache; } // 以软引用的方式对一个Employee对象的实例进行引用并保存该引用 private void cacheEmployee(Employee em) { cleanCache();// 清除垃圾引用 EmployeeRef ref = new EmployeeRef(em, q); //构建一个软引用 employeeRefs.put(em.getId(), ref); } // 依据所指定的ID号,重新获取相应Employee对象的实例 public Employee getEmployee(String ID) { Employee em = null; // 缓存中是否有该Employee实例的软引用,如果有,从软引用中取得。 if (employeeRefs.containsKey(ID)) { EmployeeRef ref = (EmployeeRef) employeeRefs.get(ID); // 获取软引用 em = (Employee) ref.get(); // 从软引用中获取实例 } // 如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例, // 并保存对这个新建实例的软引用 if (em == null) { em = new Employee(ID); System.out.println("Retrieve From EmployeeInfoCenter. ID=" + ID); this.cacheEmployee(em); } return em; } // 清除那些所软引用的Employee对象已经被回收的EmployeeRef对象 private void cleanCache() { EmployeeRef ref = null; while ((ref = (EmployeeRef) q.poll()) != null) { employeeRefs.remove(ref._key); } } // 清除Cache内的全部内容 public void clearCache() { cleanCache(); employeeRefs.clear(); System.gc(); System.runFinalization(); }}
import java.util.WeakHashMap; 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 obj) { return obj instanceof Element && ident.equals(((Element) obj).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=10; 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(); }}
输出结果
before gc{8=8, 9=9, 4=4, 5=5, 6=6, 7=7, 0=0, 1=1, 2=2, 3=3}after gc{9=9, 6=6, 0=0, 3=3}Finalizing Key 8Finalizing Key 7Finalizing Key 2Finalizing Key 1
Java -强引用&弱引用