jdk原始碼分析之WeakHashMap
基本原理
WeakHashMap特點是,當除了自身有對key的引用外,此key沒有其他引用,那麼WeakHashMap會在下次對WeakHashMap進行增刪改查操作時及時丟棄該鍵值對,節約記憶體使用,此特性使得WeakHashMap非常適合構建快取系統。
WeakHashMap是主要通過expungeStaleEntries函式的來實現移除其內部不用的entry從而達到的自動釋放記憶體的目的。基本上只要對WeakHashMap的內容進行訪問就會呼叫expungeStaleEntries函式,從而達到清除不再被外部引用的key對應的entry鍵值對。如果預先生成了WeakHashMap,而在GC以前又不曾訪問該WeakHashMap,那麼因為沒有機會呼叫expungeStaleEntries函式,因此並不會回收不再被外部引用的key對應的entry。
Entry鍵值對
WeakHashMap的鍵值對Entry繼承自WeakReference,並實現了Map.Entry
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V>
當弱引用指向的物件只能通過弱引用(沒有強引用或弱引用)訪問時,GC會清理掉該物件,之後,引用物件會被放到ReferenceQueue中。在Entry的建構函式中可以得知,通過super(key, queue)將key儲存為弱引用,通過this.value = value將value儲存為強引用。當key中的引用被gc掉之後,在下次訪問WeakHashMap(呼叫expungeStaleEntries函式)時相應的entry也會自動被移除。
/**
* Creates new entry.
*/
Entry(Object key, V value,
ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
expungeStaleEntries():清除過期的條目
從ReferenceQueue中取出過期的entry,從WeakHashMap找到對應的entry,逐一刪除
/**
* Expunges stale entries from the table.
*/
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) x;
int i = indexFor(e.hash, 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) {
if (prev == e)
table[i] = next;
else
prev.next = next;
// Must not null out e.next;
// stale entries may be in use by a HashIterator
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
}
}
}
首先通過迴圈一直從queue中取過期entry直到取完為止
for (Object x; (x = queue.poll()) != null; )
然後通過加鎖queue進行刪除過期entry的操作
synchronized (queue) {
...
}
在同步程式碼塊中先把從queue中取出的Object型別的資料強制轉化為Entry物件e,然後計算此entry在桶的位置(table陣列的下標i),然後開始遍歷entry連結串列,如果此entry是連結串列頭,設定此entry的後繼為新的連結串列頭
if (prev == e)
table[i] = next;
否則將此entry的前序節點的後繼指標指向此entry的後繼節點
else
prev.next = next;
最後設定被刪除的entry的value為null,加速垃圾回收,接著修改size
e.value = null; // Help GC
size--;
訪問WeakHashMap時,對過期條目進行清除
可以看到對WeakHashMap的增刪改查操作都會直接或者間接的呼叫expungeStaleEntries()方法,達到及時清除過期entry的目的。
此特性會到導致兩次呼叫size、get等方法可能會返回不一致的資料。
相關文章
- 死磕 java集合之WeakHashMap原始碼分析JavaHashMap原始碼
- jdk原始碼分析之TreeMapJDK原始碼
- 原始碼|jdk原始碼之HashMap分析(一)原始碼JDKHashMap
- 原始碼|jdk原始碼之HashMap分析(二)原始碼JDKHashMap
- 死磕 jdk原始碼之HashMap原始碼分析JDK原始碼HashMap
- WeakHashMap,原始碼解讀HashMap原始碼
- JDK1.8原始碼分析之HashMapJDK原始碼HashMap
- 【JDK】JDK原始碼分析-ReentrantLockJDK原始碼ReentrantLock
- 原始碼|jdk原始碼之棧、佇列及ArrayDeque分析原始碼JDK佇列
- 【JDK原始碼分析系列】ArrayBlockingQueue原始碼分析JDK原始碼BloC
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(3)JDK原始碼
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(2)JDK原始碼
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(1)JDK原始碼
- JDK原始碼分析-TreeSetJDK原始碼
- JDK中的BitMap實現之BitSet原始碼分析JDK原始碼
- JDK 1.6 HashMap 原始碼分析JDKHashMap原始碼
- JDK原始碼分析(四)——LinkedHashMapJDK原始碼HashMap
- JDK1.8原始碼分析03之idea搭建原始碼閱讀環境JDK原始碼Idea
- 原始碼分析–ArrayList(JDK1.8)原始碼JDK
- 原始碼分析–HashSet(JDK1.8)原始碼JDK
- ArrayList原始碼分析 jdk1.8原始碼JDK
- JDK 原始碼分析(1) Object類JDK原始碼Object
- HashMap原始碼分析(JDK8)HashMap原始碼JDK
- LinkedList原始碼分析(jdk1.8)原始碼JDK
- JDK1.8 hashMap原始碼分析JDKHashMap原始碼
- HashMap原始碼分析 JDK1.8HashMap原始碼JDK
- ConcurrentHashMap原始碼分析-JDK18HashMap原始碼JDK
- ArrayList原始碼分析(JDK1.8)原始碼JDK
- 原始碼分析系列1:HashMap原始碼分析(基於JDK1.8)原始碼HashMapJDK
- 併發程式設計之 ConcurrentHashMap(JDK 1.8) putVal 原始碼分析程式設計HashMapJDK原始碼
- JDK原始碼解析系列之objectJDK原始碼Object
- JDK1.8 原始碼分析(九)--LinkedHashMapJDK原始碼HashMap
- JDK1.8 原始碼分析(十) -- TreeMapJDK原始碼
- Guava 原始碼分析之 EventBus 原始碼分析Guava原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- JDK1.8原始碼分析01之學習建議(可以延伸其他原始碼學習)JDK原始碼
- JDK1.8原始碼分析筆記-HashMapJDK原始碼筆記HashMap
- 原始碼分析–ConcurrentHashMap與HashTable(JDK1.8)原始碼HashMapJDK
- 【JDK原始碼分析】淺談HashMap的原理JDK原始碼HashMap