弱引用:
public static void WeakReferenceTest(){
/**
* 弱引用的对象只能生存到下一次GC之前!
*/
String str = new String("avd");
WeakReference<String> wr = new WeakReference<String>(str);
str = null; //消除强引用
System.out.println("垃圾回收之前:"+wr.get());
System.gc();//垃圾回收
System.out.println("垃圾回收之后:"+wr.get());
}
执行结果:
垃圾回收之前:avd
垃圾回收之后:null
为什么要使用WeakHashMap?
推荐博文!来源:
互联网。
http://www.xiaoyaochong.net/wordpress/index.php/2013/08/05/java%e5%86%85%e5%ad%98%e6%b3%84%e9%9c%b2%e4%b8%8eweakhashmap/
Google Guava Cache 就是通过
清理
弱引用来回收内存的。
WeakHashMap 分析:
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>
成员变量
/**
* The default initial capacity -- MUST be a power of two.
*/
// 默认加载因子16,必须为2的幂
private static final int DEFAULT_INITIAL_CAPACITY = 16;
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
// Entry[]最大长度
private static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* The load fast used when none specified in constructor.
*/
//默认加载因子
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
private Entry[] table;
/**
* The number of key-value mappings contained in this weak hash map.
*/
// map中包含映射关系的数量
private int size;
/**
* The next size value at which to resize (capacity * load factor).
*/
// 当size的值不小于threshold时,需扩展table,并重新计算映射关系的存储位置,默认16*0.75=12
private int threshold;
/**
* The load factor for the hash table.
*/
//实际加载因子
private final float loadFactor;
/**
* Reference queue for cleared WeakEntries
*/
//引用队列,每一个弱引用entry须关联此队列,每次GC的弱引用entry会被添加到该队列
private final ReferenceQueue<K> queue = new ReferenceQueue<K>();
/**
* The number of times this WeakHashMap has been structurally modified.
* Structural modifications are those that change the number of
* mappings in the map or otherwise modify its internal structure
* (e.g., rehash). This field is used to make iterators on
* Collection-views of the map fail-fast.
*
* @see ConcurrentModificationException
*/
private volatile int modCount;
方法列表:
public Object get(Object arg-0);
public Object put(Object arg-0,Object arg-1);
public Collection values();
public void clear();
public boolean isEmpty();
public Set entrySet();
public void putAll(Map arg-0);
public int size();
public Object remove(Object arg-0);
public Set keySet();
public boolean containsKey(Object arg-0);
public boolean containsValue(Object arg-0);
public boolean equals(Object arg-0);
public String toString();
public int hashCode();
成员变量:
/**
* Value representing null keys inside tables.
*/
// key为null时,用NULL_KEY取代
private static final Object NULL_KEY = new Object();
public Object put(Object arg-0,Object arg-1);
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for this key, the old
* value is replaced.
*/
public V put(K key, V value) {
K k = (K) maskNull(key);//如果key == null,则key用NULL_KEY代替
int h = HashMap.hash(k.hashCode());
Entry[] tab = getTable();//清理map中无效的引用
int i = indexFor(h, tab.length);
for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
if (h == e.hash && eq(k, e.get())) {
V oldValue = e.value;
if (value != oldValue)
e.value = value;
return oldValue;
}
}
modCount++;
Entry<K,V> e = tab[i];
tab[i] = new Entry<K,V>(k, value, queue, h, e);//将新的元素添加到哈希表
if (++size >= threshold)
resize(tab.length * 2);//扩展Entry[]到原来的2倍
return null;
}
/**
* Use NULL_KEY for key if it is null.
*/
private static Object maskNull(Object key) {
return (key == null ? NULL_KEY : key);
}
/**
* Applies a supplemental hash function to a given hashCode, which
* defends against poor quality hash functions. This is critical
* because HashMap uses power-of-two length hash tables, that
* otherwise encounter collisions for hashCodes that do not differ
* in lower bits. Note: Null keys always map to hash 0, thus index 0.
*/
// hash 函数
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
/**
* Returns index for hash code h.
*/
// 重新计算entry的桶的位置
static int indexFor(int h, int length) {
return h & (length-1);
}
/**
* Rehashes the contents of this map into a new array with a
* larger capacity. This method is called automatically when the
* number of keys in this map reaches its threshold.
*
* If current capacity is MAXIMUM_CAPACITY, this method does not
* resize the map, but sets threshold to Integer.MAX_VALUE.
* This has the effect of preventing future calls.
*/
//扩展Entry[]的容量
void resize(int newCapacity) {
Entry[] oldTable = getTable();
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(oldTable, newTable);
table = newTable;
/*
* If ignoring null elements and processing ref queue caused massive
* shrinkage, then restore old table. This should be rare, but avoids
* unbounded expansion of garbage-filled tables.
*/
//扩展容量之后,剩余元素很少,则收缩哈希表的容量到上一次未扩容是的大小,减少内存占用。
if (size >= threshold / 2) {
threshold = (int)(newCapacity * loadFactor);
} else {
expungeStaleEntries();
transfer(newTable, oldTable);
table = oldTable;
}
}
/** Transfers all entries from src to dest tables */
//将旧哈希表中的映射关系添加到新哈希表中
private void transfer(Entry[] src, Entry[] dest) {
for (int j = 0; j < src.length; ++j) {
Entry<K,V> e = src[j];
src[j] = null;
while (e != null) {
Entry<K,V> next = e.next; // e的下一个entry
Object key = e.get(); // T get():返回注册的引用对象,如果此对象已回收,将返回null
if (key == null) { // key == null, 解除对下一个entry 和value的引用
e.next = null; // Help GC
e.value = null; // " "
size--;//不放到新哈希表中,所以其size应-1
} else {
int i = indexFor(e.hash, dest.length);
e.next = dest[i];
dest[i] = e;
}
e = next;//e指向下一个entry
}
}
}
/**
* Returns the table after first expunging stale entries.
*/
//清除过时无效的引用
private Entry[] getTable() {
expungeStaleEntries();
return table;
}
/**
* Expunges stale entries from the table.
*/
private void expungeStaleEntries() {
Entry<K,V> e;
while ( (e = (Entry<K,V>) queue.poll()) != null) {//轮询此队列 ,再遍历对应的桶
int h = e.hash;
int i = indexFor(h, table.length);
Entry<K,V> prev = table[i];//对应桶的第一个元素
Entry<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;//指向下一个元素
if (p == e) { //p == e 说明该对象存在于队列之中,说明已经被垃圾回收器回收。
if (prev == e)//prev == e说明桶的第一个元素被回收
table[i] = next;//table[i]存放其下一个元素,prev和p指向next
else
prev.next = next;//prev越过p指向p.next
//解除引用,结束循环
e.next = null; // Help GC
e.value = null; // " "
size--;
break;
}
//说明元素p未被回收
prev = p;
p = next;//使p指向下一个元素
}
}
}
第一个元素被回收的情况:
初始状态:
第一次循环:移除table[i]位置的元素,下一个元素置于table[i]位置,该桶的循环结束
第一个元素不被回收的情况:
第一次循环:
第二次循环移除第二个元素:这个桶的循环结束
/**
* The entries in this hash table extend WeakReference, using its main ref
* field as the key.
*/
//哈希表中存储 的弱引用对象,最终继承自 Reference 抽象类。
private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V> {
private V value;
private final int hash;
private Entry<K,V> next;
/**
* Creates new entry.
*/
Entry(K key, V value,
ReferenceQueue<K> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
public K getKey() {
return WeakHashMap.<K>unmaskNull(get());//获取当前映射关系的key.
}
public V getValue() {
return value;
}
public V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
public int hashCode() {
Object k = getKey();
Object v = getValue();
return ((k==null ? 0 : k.hashCode()) ^
(v==null ? 0 : v.hashCode()));
}
public String toString() {
return getKey() + "=" + getValue();
}
}
/**
* Returns internal representation of null key back to caller as null.
*/
//返回映射关系的key,若key为NULL_KEY,则转换为null.
private static <K> K unmaskNull(Object key) {
return (K) (key == NULL_KEY ? null : key);
}
ReferenceQueue以及Reference在WeakHashMap中的运用!
当添加一个映射关系时,将key及queue关联到Reference!
/**
* Reference queue for cleared WeakEntries
*/
private final ReferenceQueue<K> queue = new ReferenceQueue<K>();
public V put(K key, V value) {
K k = (K) maskNull(key);
int h = HashMap.hash(k.hashCode());
Entry[] tab = getTable();
int i = indexFor(h, tab.length);
for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
if (h == e.hash && eq(k, e.get())) {
V oldValue = e.value;
if (value != oldValue)
e.value = value;
return oldValue;
}
}
modCount++;
Entry<K,V> e = tab[i];
tab[i] = new Entry<K,V>(k, value, queue, h, e);
if (++size >= threshold)
resize(tab.length * 2);
return null;
}
private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V> {
private V value;
private final int hash;
private Entry<K,V> next;
/**
* Creates new entry.
*/
Entry(K key, V value,
ReferenceQueue<K> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
public K getKey() {
return WeakHashMap.<K>unmaskNull(get());
}
public V getValue() {
return value;
}
public V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
public int hashCode() {
Object k = getKey();
Object v = getValue();
return ((k==null ? 0 : k.hashCode()) ^
(v==null ? 0 : v.hashCode()));
}
public String toString() {
return getKey() + "=" + getValue();
}
}
/**
* Creates a new weak reference that refers to the given object and is
* registered with the given queue.
*/
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
private T referent; /* Treated specially by GC */
ReferenceQueue<? super T> queue;
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
当垃圾回收时:回收弱引用中的key
Reference的内部类线程被调用,将被回收的弱引用对象添加到队列
private static class ReferenceHandler extends Thread {
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
public void run() {
for (;;) {
Reference r;
synchronized (lock) {
if (pending != null) {
r = pending;
Reference rn = r.next;
pending = (rn == r) ? null : rn;
r.next = r;
} else {
try {
lock.wait();
} catch (InterruptedException x) { }
continue;
}
}
// Fast path for cleaners
if (r instanceof Cleaner) {
((Cleaner)r).clean();
continue;
}
ReferenceQueue q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
}
}
}
private volatile Reference<? extends T> head = null;
private long queueLength = 0;
boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
synchronized (r) {
if (r.queue == ENQUEUED) return false;
synchronized (lock) {
r.queue = ENQUEUED;
r.next = (head == null) ? r : head;
head = r;
queueLength++;
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(1);
}
lock.notifyAll();
return true;
}
}
}
toString()也调用expungeStaleEntries();
public String toString() {
Iterator<Entry<K,V>> i = entrySet().iterator();
if (! i.hasNext())
return "{}";
StringBuilder sb = new StringBuilder();
sb.append('{');
for (;;) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
sb.append(key == this ? "(this Map)" : key);
sb.append('=');
sb.append(value == this ? "(this Map)" : value);
if (! i.hasNext())
return sb.append('}').toString();
sb.append(", ");
}
}
private abstract class HashIterator<T> implements Iterator<T> {
int index;
HashIterator() {
index = (size() != 0 ? table.length : 0);
}
}
/**
* Returns the number of key-value mappings in this map.
* This result is a snapshot, and may not reflect unprocessed
* entries that will be removed before next attempted access
* because they are no longer referenced.
*/
public int size() {
if (size == 0)
return 0;
expungeStaleEntries();
return size;
}
★★★★★
★★★★★
WeakHashMap并不是你啥也干他就能自动释放内部不用的对象的,而是在你
访问它的内容的时候释放内部不用的对象。
继承自WeakReference的
Entry对象才是所说的弱引用对象。
private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V>
弱引用对象中的key在GC时被回收:如下图可知key已经被回收,但entry还存在,value存在于entry内部。
GC之后,再次访问
WeakHashMap,调用
private
void
expungeStaleEntries()方法时清除entry和value对象。
推荐博客:
来源:
互联网。
http://www.cnblogs.com/redcreen/archive/2011/02/15/1955289.html