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原始碼分析之PriorityQueueJDK原始碼
- jdk原始碼分析之ArrayListJDK原始碼
- jdk原始碼分析之HashMapJDK原始碼HashMap
- jdk原始碼分析之CopyOnWriteArrayListJDK原始碼
- 原始碼|jdk原始碼之HashMap分析(一)原始碼JDKHashMap
- 原始碼|jdk原始碼之HashMap分析(二)原始碼JDKHashMap
- jdk原始碼分析之LinkedListJDK原始碼
- jdk原始碼分析之ConcurrentHashMapJDK原始碼HashMap
- jdk原始碼分析之LinkedHashMapJDK原始碼HashMap
- 死磕 jdk原始碼之HashMap原始碼分析JDK原始碼HashMap
- WeakHashMap,原始碼解讀HashMap原始碼
- Java WeakHashMap 原始碼解析JavaHashMap原始碼
- JDK1.8原始碼分析之HashMapJDK原始碼HashMap
- jdk1.8原始碼之HashMap分析JDK原始碼HashMap
- 原始碼|jdk原始碼之棧、佇列及ArrayDeque分析原始碼JDK佇列
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(1)JDK原始碼
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(2)JDK原始碼
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(3)JDK原始碼
- 【JDK】JDK原始碼分析-ReentrantLockJDK原始碼ReentrantLock
- 【JDK原始碼分析系列】ArrayBlockingQueue原始碼分析JDK原始碼BloC
- JDK原始碼分析-TreeSetJDK原始碼
- 【JUC】JDK1.8原始碼分析之CyclicBarrier(四)JDK原始碼
- 【JUC】JDK1.8原始碼分析之CountDownLatch(五)JDK原始碼CountDownLatch
- 【JUC】JDK1.8原始碼分析之AbstractQueuedSynchronizer(二)JDK原始碼
- 【JUC】JDK1.8原始碼分析之Semaphore(六)JDK原始碼
- 【JUC】JDK1.8原始碼分析之LockSupport(一)JDK原始碼
- JDK 1.6 HashMap 原始碼分析JDKHashMap原始碼
- HashMap原始碼分析(JDK 1.8)HashMap原始碼JDK
- JDK中的BitMap實現之BitSet原始碼分析JDK原始碼
- 【JUC】JDK1.8原始碼分析之ThreadPoolExecutor(一)JDK原始碼thread
- 【JUC】JDK1.8原始碼分析之ReentrantLock(三)JDK原始碼ReentrantLock
- 【JUC】JDK1.8原始碼分析之ConcurrentHashMap(一)JDK原始碼HashMap
- 【集合框架】JDK1.8原始碼分析之HashMap(一)框架JDK原始碼HashMap
- 【集合框架】JDK1.8原始碼分析之ArrayList(六)框架JDK原始碼
- 【集合框架】JDK1.8原始碼分析之TreeMap(五)框架JDK原始碼
- 【JUC】JDK1.8原始碼分析之LinkedBlockingQueue(四)JDK原始碼BloC