認識 WeakHashMap !

弱引用:

     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














相關文章
相關標籤/搜索