A a = new A();
就是強引用GC
不會回收強引用,即便內存不足的狀況下也不會,寧肯OutOfMemeryError
SoftReference
的主要特色是具備較強的引用功能。OutOfMemoryError
以前,被設置爲null。WeakReference
在垃圾回收器運行時,必定會被回收,而不像 SoftReference 須要條件。可是,若對象的引用關係複雜,則可能須要屢次回收才能達到目的。PhantomReference
主 要 用 於 輔 助finalize
方法。PhantomReference
對象執行完了 finalize
方法後,成爲 Unreachable Objects
。但還未被回收,在此時,能夠輔助 finalize
進行一些後期的回收工做。put函數數據結構
public V put(K key, V value) { //若是key是null,則使用定義的常量NULL_KEY代替null。 Object k = maskNull(key); int h = hash(k); Entry<K,V>[] tab = getTable(); int i = indexFor(h, tab.length); for (Entry<K,V> e = tab[i]; e != null; e = e.next) { //若是原來有這個key,就替換並返回舊value 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, value, queue, h, e); if (++size >= threshold) resize(tab.length * 2); return null; }
WeakHashMap
的Entry
實現,繼承了WeakReference
,每個Entry都有其屬於的ReferenceQueue,使得後面JVM在垃圾回收後,查找Reference對象組件pending鏈,並將Entry移動到ReferenceQueue成爲可能。函數
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> { V value; final int hash; Entry<K,V> next; 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; } @SuppressWarnings("unchecked") public K getKey() { return (K) WeakHashMap.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; K k1 = getKey(); Object k2 = e.getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) { V v1 = getValue(); Object v2 = e.getValue(); if (v1 == v2 || (v1 != null && v1.equals(v2))) return true; } return false; } public int hashCode() { K k = getKey(); V v = getValue(); return Objects.hashCode(k) ^ Objects.hashCode(v); } public String toString() { return getKey() + "=" + getValue(); } }
Entry的構造函數中調用super(key, queue);
將Key處理成Reference
:this
Reference(T referent, ReferenceQueue<? super T> queue) { this.referent = referent; this.queue = (queue == null) ? ReferenceQueue.NULL : queue; }
與HashMap
比較一下,Entry
不直接引用Key
這個對象,而是將引用關係放到了父類WeakReference
中,能夠看出WeakHashMap
將傳入的key
包裝成了WeakReference
,並傳入了一個ReferenceQueue
;可是弱引用的實現細節仍是不清楚......線程
static private class Lock { }; private static Lock lock = new Lock(); //pending是一個鏈表結構 private static Reference<Object> pending = null; static { ThreadGroup tg = Thread.currentThread().getThreadGroup(); for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent()); Thread handler = new ReferenceHandler(tg, "Reference Handler"); /* If there were a special system-only priority greater than * MAX_PRIORITY, it would be used here */ handler.setPriority(Thread.MAX_PRIORITY); handler.setDaemon(true); handler.start(); }
線程的優先級設成MAX
,是一個什麼樣的線程須要如此高的權限?pending 、lock 都被static
聲明,lock.wait
以後誰來喚醒,互聯網上一頓蒐羅,才明白JVM參與了這些事。 用通俗的話把JVM乾的事串一下: 假設,WeakHashMap
對象裏面已經保存了不少對象的引用。JVM
使用進行CMS GC垃圾回收的時候,會建立一個ConcurrentMarkSweepThread
(簡稱CMST)線程去進行垃圾回收,ConcurrentMarkSweepThread
線程被建立的同時會建立一個SurrogateLockerThread
(簡稱SLT)線程而且啓動它,SLT
啓動以後,處於等待階段。 CMST開始垃圾回收時,會發一個消息給SLT讓它去獲取Java層Reference
對象的全局鎖:lock
。 直到CMS GC完畢以後,JVM
會將WeakHashMap
中全部被回收的對象所屬的WeakReference
容器對象放入到Reference
的pending
屬性當中(每次GC完畢以後,pending
屬性基本上都不會爲null
了),而後通知SLT釋放而且notify
全局鎖: lock
。此時激活了ReferenceHandler
線程的run
方法,使其脫離wait狀態,開始工做了。ReferenceHandler
這個線程會將pending
中的全部WeakReference
對象都移動到它們各自的列隊當中,好比當前這個WeakReference
屬於某個WeakHashMap
對象,那麼它就會被放入相應的ReferenceQueue
列隊裏面(該列隊是鏈表結構)。code
Gc完成後, pending賦值,lock釋放,此時ReferenceHandler
獲取lock鎖,將 pending
中的Reference
對象壓入了各自的 ReferenceQueue
中對象
pending
是Reference
對象,給JVM使用的數據結構。pending.discovered
返回下一個Reference
對象。繼承
// MAX_PRIORITY線程將pending的references所有入列 private static class ReferenceHandler extends Thread { ReferenceHandler(ThreadGroup g, String name) { super(g, name); } public void run() { for (;;) { Reference<Object> r; synchronized (lock) { if (pending != null) { r = pending; pending = r.discovered; r.discovered = null; } else { try { try { lock.wait(); } catch (OutOfMemoryError x) { } } catch (InterruptedException x) { } continue; } } // Fast path for cleaners if (r instanceof Cleaner) { ((Cleaner)r).clean(); continue; } ReferenceQueue<Object> q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); } } }
當GC以後,WeakHashMap
對象裏面get、put數據或者調用size方法的時候,WeakHashMap
比HashMap
多了一個 expungeStaleEntries()
方法內存
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; } } } }
expungeStaleEntries
方法 就是將ReferenceQueue
列隊中的WeakReference
依依poll
出來去和Entry[]
數據作比較,若是發現相同的,則說明這個Entry
所保存的對象已經被GC掉了,那麼將Entry[]
內的Entry
對象剔除掉,這樣就把被GC掉的 WeakReference
對應的Entry
從WeakHashMap
中移除了。ci
Thanks for reading! want moreget