国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

WeakHashMap

2019-11-15 00:06:47
字體:
供稿:網(wǎng)友
WeakHashMap

WeakHashMap,當(dāng)除了自身有對key的引用外,此key沒有其他引用那么此map會自動丟棄此值。

code

此例子中聲明了兩個Map對象,一個是HashMap,一個是WeakHashMap,同時向兩個map中放入a、b兩個對象,當(dāng)HashMap.remove掉a 并且將a、b都指向null時,WeakHashMap中的a將自動被回收掉。出現(xiàn)這個狀況的原因是,對于a對象而言,當(dāng)HashMap.remove掉并且將a指向null后,除了WeakHashMap中還保存a外已經(jīng)沒有指向a的指針了,所以WeakHashMap會自動舍棄掉a,而對于b對象雖然指向了null,但HashMap中還有指向b的指針,所以WeakHashMap將會保留。

public class Test {      public static void main(String[] args) throws Exception {          String a = new String("a");          String b = new String("b");          Map weakmap = new WeakHashMap();          Map map = new HashMap();          map.put(a, "aaa");          map.put(b, "bbb");                    weakmap.put(a, "aaa");          weakmap.put(b, "bbb");                    map.remove(a);                    a=null;          b=null;                    System.gc();          Iterator i = map.entrySet().iterator();          while (i.hasNext()) {              Map.Entry en = (Map.Entry)i.next();              System.out.我是天王蓋地虎的分割線

WeakHashMap是主要通過expungeStaleEntries這個函數(shù)的來實現(xiàn)移除其內(nèi)部不用的條目從而達到的自動釋放內(nèi)存的目的的.基本上只要對WeakHashMap的內(nèi)容進行訪問就會調(diào)用這個函數(shù),從而達到清除其內(nèi)部不在為外部引用的條目。但是如果預(yù)先生成了WeakHashMap,而在GC以前又不曾訪問該WeakHashMap,那不是就不能釋放內(nèi)存了嗎?

public class WeakHashMapTest1 {    public static void main(String[] args) {        List<WeakHashMap<long[][], long[][]>> maps = new ArrayList<WeakHashMap<long[][], long[][]>>();        for (int i = 0; i < 1000000; i++) {            WeakHashMap<long[][], long[][]> d = new WeakHashMap<long[][], long[][]>();            d.put(new long[1000][1000], new long[1000][1000]);            maps.add(d);            System.gc();            System.err.println(i);        }    }}

該測試跑不了幾步循環(huán)就內(nèi)存溢出了。果不其然,WeakHashMap這個時候并沒有自動幫我們釋放不用的內(nèi)存。

image

public class WeakHashMapTest2 {       public static void main(String[] args) throws Exception {              List<WeakHashMap<long[][], long[][]>> maps = new ArrayList<WeakHashMap<long[][], long[][]>>();              for (int i = 0; i < 1000; i++) {                     WeakHashMap<long[][], long[][]> d = new WeakHashMap<long[][], long[][]>();                     d.put(new long[1000][1000], new long[1000][1000]);                     maps.add(d);                     System.gc();                     System.err.println(i);                     for (int j = 0; j < i; j++) {                            System.err.println(j + " size" + maps.get(j).size());                     }              }       }}

image

這次測試輸出正常,不在出現(xiàn)內(nèi)存溢出問題??偨Y(jié)來說:WeakHashMap并不是你啥也干他就能自動釋放內(nèi)部不用的對象的,而是在你訪問它的內(nèi)容的時候釋放內(nèi)部不用的對象。

WeakHashMap實現(xiàn)弱引用,是因為它的Entry<K,V>是繼承自WeakReference<K>的。在WeakHashMap$Entry<K,V>的類定義及構(gòu)造函數(shù)里面是這樣寫的:

private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V> 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; }

請注意它構(gòu)造父類的語句:“super(key, queue);”,傳入的是key,因此key才是進行弱引用的,value是直接強引用關(guān)聯(lián)在this.value之中。在System.gc()時,key中的byte數(shù)組進行了回收,而value依然保持(value被強關(guān)聯(lián)到entry上,entry又關(guān)聯(lián)在map中,map關(guān)聯(lián)在arrayList中)。

如何證明key中的byte被回收了呢?可以通過內(nèi)存溢出時導(dǎo)出的內(nèi)存鏡像進行分析,也可以通過如下的小測試得出結(jié)論:

for (int i = 0; i < 10000; i++) {        WeakHashMap<long[][], Object> d = new WeakHashMap<long[][], Object>();        d.put(newlong[1000][1000], new Object());        maps.add(d);               System.gc();        System.err.println(i); }

上面的代碼,即使執(zhí)行10000次也沒有問題,證明key中的long數(shù)組確實被回收了。for循環(huán)中每次都new一個新的WeakHashMap,在put操作后,雖然GC將WeakReference的key中的long數(shù)組回收了,并將事件通知到了ReferenceQueue,但后續(xù)卻沒有相應(yīng)的動作去觸發(fā)WeakHashMap 去處理 ReferenceQueue。所以 WeakReference 包裝的key依然存在在WeakHashMap中,其對應(yīng)的value也當(dāng)然存在。(就是說long被回收掉了,但是new Object沒有被回收掉)

那value是何時被清除的呢?

對兩個例子進行分析可知,例子二中的maps.get(j).size()觸發(fā)了value的回收,那又如何觸發(fā)的呢.查看WeakHashMap源碼可知,size方法調(diào)用了expungeStaleEntries方法,該方法對vm要回收的的entry(quene中)進行遍歷,并將entry的value置空,回收了內(nèi)存。所以效果是key在GC的時候被清除,value在key清除后訪問WeakHashMap被清除。

疑問:key的quene與map的quene是同一個quene,poll操作會減少一個reference,那問題是key如果先被清除,expungeStaleEntries遍歷quene時那個被回收的key對應(yīng)的entry還能取出來么???

關(guān)于執(zhí)行System.GC時,key中的long數(shù)據(jù)如何被回收了,請見WeakReference referenceQueneWeakHashMap

public class WeakHashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>

以弱鍵實現(xiàn)的基于哈希表的 Map。在 WeakHashMap 中,當(dāng)某個鍵不再正常使用時,將自動移除其條目。更精確地說,對于一個給定的鍵,其映射的存在并不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成為可終止的,被終止,然后被回收。丟棄某個鍵時,其條目從映射中有效地移除,因此,該類的行為與其他的 Map 實現(xiàn)有所不同。null 值和 null 鍵都被支持。該類具有與 HashMap 類相似的性能特征,并具有相同的效能參數(shù)初始容量 和加載因子。

像大多數(shù)集合類一樣,該類是不同步的??梢允褂?Collections.synchronizedMap 方法來構(gòu)造同步的 WeakHashMap。

該類主要與這樣的鍵對象一起使用,其 equals 方法使用 == 運算符來測試對象標(biāo)識。

一旦這種鍵被丟棄,就永遠無法再創(chuàng)建了,所以,過段時間后在 WeakHashMap 中查找此鍵是不可能的,不必對其項已移除而感到驚訝。該類十分適合與 equals 方法不是基于對象標(biāo)識的鍵對象一起使用,比如,String 實例。

然而,對于這種可重新創(chuàng)建的鍵對象,鍵若丟棄,就自動移除 WeakHashMap 條目,這種表現(xiàn)令人疑惑。

WeakHashMap 類的行為部分取決于垃圾回收器的動作,所以,幾個常見的(雖然不是必需的)Map 常量不支持此類。

因為垃圾回收器在任何時候都可能丟棄鍵,WeakHashMap 就像是一個被悄悄移除條目的未知線程。特別地,即使對 WeakHashMap 實例進行同步,并且沒有調(diào)用任何賦值方法,在一段時間后 ,size 方法也可能返回較小的值,對于 isEmpty 方法,可能返回 false,然后返回 true,對于給定的鍵,containsKey 方法可能返回 true 然后返回 false,對于給定的鍵,get 方法可能返回一個值,但接著返回 null,對于以前出現(xiàn)在映射中的鍵,put 方法返回 null,而 remove 方法返回 false,對于鍵集、值集、項集進行的檢查,生成的元素數(shù)量越來越少。

WeakHashMap 中的每個鍵對象間接地存儲為一個弱引用的指示對象。因此,不管是在映射內(nèi)還是在映射之外,只有在垃圾回收器清除某個鍵的弱引用之后,該鍵才會自動移除。

實現(xiàn)注意事項:WeakHashMap 中的值對象由普通的強引用保持。因此應(yīng)該小心謹慎,確保值對象不會直接或間接地強引用其自身的鍵,因為這會阻止鍵的丟棄。注意,值對象可以通過 WeakHashMap 本身間接引用其對應(yīng)的鍵;這就是說,某個值對象可能強引用某個其他的鍵對象,而與該鍵對象相關(guān)聯(lián)的值對象轉(zhuǎn)而強引用第一個值對象的鍵。處理此問題的一種方法是,在插入前將值自身包裝在 WeakReferences 中,如:m.put(key, new WeakReference(value)),然后,分別用 get 進行解包。

該類所有“collection 視圖方法”返回的迭代器均是快速失敗的:在迭代器創(chuàng)建之后,如果從結(jié)構(gòu)上對映射進行修改,除非通過迭代器自身的 remove 或 add 方法,其他任何時間任何方式的修改,迭代器都將拋出 ConcurrentModificationException。因此,面對并發(fā)的修改,迭代器很快就完全失敗,而不是冒著在將來不確定的時間任意發(fā)生不確定行為的風(fēng)險。注意,迭代器的快速失敗行為不能得到保證,一般來說,存在不同步的并發(fā)修改時,不可能作出任何堅決的保證。快速失敗迭代器盡最大努力拋出 ConcurrentModificationException。因此,編寫依賴于此異常程序的方式是錯誤的。

正確做法是:迭代器的快速失敗行為應(yīng)該僅用于檢測 bug。注意1: null 值和 null 鍵都被支持。注意2:不是線程安全的。注意3:迭代器的快速失敗行為不能得到保證。注意4:WeakHashMap是無序的。注意5: 確保值對象不會直接或間接地強引用其自身的鍵,

因為這會阻止鍵的丟棄。但是,值對象可以通過 WeakHashMap 本身間接引用其對應(yīng)的鍵;這就是說,某個值對象可能強引用某個其他的鍵對象,而與該鍵對象相關(guān)聯(lián)的值對象轉(zhuǎn)而強引用第一個值對象的鍵,這時就形成了環(huán)路。處理此問題的一種方法是,在插入前將值自身包裝在WeakReferences中,如:m.put(key, new WeakReference(value)),然后,分別用 get 進行解包。

我是天王蓋地虎的分割線
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 远安县| 昔阳县| 朝阳区| 麻江县| 封丘县| 商水县| 华容县| 南皮县| 景洪市| 嵊州市| 建宁县| 丰都县| 乌兰县| 延庆县| 电白县| 饶平县| 恩施市| 陆川县| 平阳县| 元朗区| 威海市| 乌拉特后旗| 盐源县| 绥滨县| 姚安县| 木里| 洮南市| 黔南| 屯昌县| 商城县| 团风县| 临潭县| 综艺| 织金县| 平远县| 连云港市| 铅山县| 富源县| 霍林郭勒市| 长葛市| 香港|