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