亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

解析WeakHashMap與HashMap的區別詳解

2019-11-26 16:06:22
字體:
來源:轉載
供稿:網友
WeakHashMap,此種Map的特點是,當除了自身有對key的引用外,此key沒有其他引用那么此map會自動丟棄此值,
見實例:此例子中聲明了兩個Map對象,一個是HashMap,一個是WeakHashMap,同時向兩個map中放入a、b兩個對象,當HashMap  remove掉a 并且將a、b都指向null時,WeakHashMap中的a將自動被回收掉。出現這個狀況的原因是,對于a對象而言,當HashMap  remove掉并且將a指向null后,除了WeakHashMap中還保存a外已經沒有指向a的指針了,所以WeakHashMap會自動舍棄掉a,而對于b對象雖然指向了null,但HashMap中還有指向b的指針,所以
WeakHashMap將會保留
復制代碼 代碼如下:

package test; 

import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map; 
import java.util.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.println("map:"+en.getKey()+":"+en.getValue()); 
        } 

        Iterator j = weakmap.entrySet().iterator(); 
        while (j.hasNext()) { 
            Map.Entry en = (Map.Entry)j.next(); 
            System.out.println("weakmap:"+en.getKey()+":"+en.getValue()); 

        } 
    } 

     


先把問題說清楚:
WeakHashMap是主要通過expungeStaleEntries這個函數的來實現移除其內部不用的條目從而達到的自動釋放內存的目的的.基本上只要對WeakHashMap的內容進行訪問就會調用這個函數,從而達到清除其內部不在為外部引用的條目。但是如果預先生成了WeakHashMap,而在GC以前又不曾訪問該WeakHashMap,那不是就不能釋放內存了嗎?
對應的兩個測試案例:
WeakHashMapTest1:
復制代碼 代碼如下:

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

由于Java默認內存是64M,所以再不改變內存參數的情況下,該測試跑不了幾步循環就內存溢出了。果不其然,WeakHashMap這個時候并沒有自動幫我們釋放不用的內存。
WeakHashMapTest2:
復制代碼 代碼如下:

public class WeakHashMapTest2 {
public static void main(String[] args) throws Exception {
List<WeakHashMap<byte[][], byte[][]>> maps = new ArrayList<WeakHashMap<byte[][], byte[][]>>();
for (int i = 0; i < 1000; i++) {
WeakHashMap<byte[][], byte[][]> d = new WeakHashMap<byte[][], byte[][]>();
d.put(new byte[1000][1000], new byte[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());
}
}
}
}

這次測試輸出正常,不在出現內存溢出問題.
總結來說:WeakHashMap并不是你啥也干他就能自動釋放內部不用的對象的,而是在你訪問它的內容的時候釋放內部不用的對象
問題講清楚了,現在我們來梳理一下.了解清楚其中的奧秘.
WeakHashMap實現弱引用,是因為它的Entry<K,V>是繼承自WeakReference<K>的
在WeakHashMap$Entry<K,V>的類定義及構造函數里面是這樣寫的:
復制代碼 代碼如下:

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;
}

請注意它構造父類的語句:“super(key, queue);”,傳入的是key,因此key才是進行弱引用的,value是直接強引用關聯在this.value之中.在System.gc()時,key中的byte數組進行了回收,而value依然保持(value被強關聯到entry上,entry又關聯在map中,map關聯在arrayList中.).
如何證明key中的byte被回收了呢?可以通過內存溢出時導出的內存鏡像進行分析,也可以通過如下的小測試得出結論:
把上面的value用小對象代替,
復制代碼 代碼如下:

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

上面的代碼,即使執行10000次也沒有問題,證明key中的byte數組確實被回收了。
for循環中每次都new一個新的WeakHashMap,在put操作后,雖然GC將WeakReference的key中的byte數組回收了,并將事件通知到了ReferenceQueue,但后續卻沒有相應的動作去觸發 WeakHashMap 去處理 ReferenceQueue
所以 WeakReference 包裝的key依然存在在WeakHashMap中,其對應的value也當然存在。
 那value是何時被清除的呢?
對兩個例子進行分析可知,例子二中的maps.get(j).size()觸發了value的回收,那又如何觸發的呢.查看WeakHashMap源碼可知,size方法調用了expungeStaleEntries方法,該方法對vm要回收的的entry(quene中)進行遍歷,并將entry的value置空,回收了內存.
所以效果是key在GC的時候被清除,value在key清除后訪問WeakHashMap被清除.
疑問:key的quene與map的quene是同一個quene,poll操作會減少一個reference,那問題是key如果先被清除,expungeStaleEntries遍歷quene時那個被回收的key對應的entry還能取出來么???
關于執行System.GC時,key中的byte數據如何被回收了,請見WeakReference referenceQuene
WeakHashMap
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>
以弱鍵實現的基于哈希表的 Map。在 WeakHashMap 中,當某個鍵不再正常使用時,將自動移除其條目。
更精確地說,對于一個給定的鍵,其映射的存在并不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成為可終止的,被終止,然后被回收。
丟棄某個鍵時,其條目從映射中有效地移除,因此,該類的行為與其他的 Map 實現有所不同。
null 值和 null 鍵都被支持。該類具有與 HashMap 類相似的性能特征,并具有相同的效能參數初始容量 和加載因子。
像大多數集合類一樣,該類是不同步的??梢允褂?Collections.synchronizedMap 方法來構造同步的 WeakHashMap。
該類主要與這樣的鍵對象一起使用,其 equals 方法使用 == 運算符來測試對象標識。
一旦這種鍵被丟棄,就永遠無法再創建了,所以,過段時間后在 WeakHashMap 中查找此鍵是不可能的,不必對其項已移除而感到驚訝。
該類十分適合與 equals 方法不是基于對象標識的鍵對象一起使用,比如,String 實例。
然而,對于這種可重新創建的鍵對象,鍵若丟棄,就自動移除 WeakHashMap 條目,這種表現令人疑惑。
WeakHashMap 類的行為部分取決于垃圾回收器的動作,所以,幾個常見的(雖然不是必需的)Map 常量不支持此類。
因為垃圾回收器在任何時候都可能丟棄鍵,WeakHashMap 就像是一個被悄悄移除條目的未知線程。
特別地,即使對 WeakHashMap 實例進行同步,并且沒有調用任何賦值方法,在一段時間后 ,size 方法也可能返回較小的值,
對于 isEmpty 方法,可能返回 false,然后返回 true,對于給定的鍵,containsKey 方法可能返回 true 然后返回 false,對于給定的鍵,
get 方法可能返回一個值,但接著返回 null,對于以前出現在映射中的鍵,put 方法返回 null,而 remove 方法返回 false,
對于鍵集、值集、項集進行的檢查,生成的元素數量越來越少。
WeakHashMap 中的每個鍵對象間接地存儲為一個弱引用的指示對象。因此,不管是在映射內還是在映射之外,
只有在垃圾回收器清除某個鍵的弱引用之后,該鍵才會自動移除。
實現注意事項:WeakHashMap 中的值對象由普通的強引用保持。因此應該小心謹慎,確保值對象不會直接或間接地強引用其自身的鍵,
因為這會阻止鍵的丟棄。注意,值對象可以通過 WeakHashMap 本身間接引用其對應的鍵;
這就是說,某個值對象可能強引用某個其他的鍵對象,而與該鍵對象相關聯的值對象轉而強引用第一個值對象的鍵。
處理此問題的一種方法是,在插入前將值自身包裝在 WeakReferences 中,如:m.put(key, new WeakReference(value)),
然后,分別用 get 進行解包。
該類所有“collection 視圖方法”返回的迭代器均是快速失敗的:在迭代器創建之后,
如果從結構上對映射進行修改,除非通過迭代器自身的 remove 或 add 方法,其他任何時間任何方式的修改,
迭代器都將拋出 ConcurrentModificationException。因此,面對并發的修改,迭代器很快就完全失敗,
而不是冒著在將來不確定的時間任意發生不確定行為的風險。
注意,迭代器的快速失敗行為不能得到保證,一般來說,存在不同步的并發修改時,不可能作出任何堅決的保證。
快速失敗迭代器盡最大努力拋出 ConcurrentModificationException。因此,編寫依賴于此異常程序的方式是錯誤的,
正確做法是:迭代器的快速失敗行為應該僅用于檢測 bug。
注意1:null 值和 null 鍵都被支持。
注意2:不是線程安全的。
注意3:迭代器的快速失敗行為不能得到保證。
注意4:WeakHashMap是無序的。
注意5:確保值對象不會直接或間接地強引用其自身的鍵,
因為這會阻止鍵的丟棄。但是,值對象可以通過 WeakHashMap 本身間接引用其對應的鍵;
這就是說,某個值對象可能強引用某個其他的鍵對象,而與該鍵對象相關聯的值對象轉而強引用第一個值對象的鍵,這時就形成了環路。
處理此問題的一種方法是,在插入前將值自身包裝在WeakReferences中,如:m.put(key, new WeakReference(value)),
然后,分別用 get 進行解包。如實例1.
實例1:
復制代碼 代碼如下:

import java.lang.ref.WeakReference;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class Test {
 /**
  * @param args
  */
 public static void main(String[] args) {
  WeakHashMap<Integer,WeakReference<People>> map=new WeakHashMap<Integer,WeakReference<People>>();
  People p1=new People("robin",1,28);
  People p2=new People("robin",2,29);
  People p3=new People("harry",3,30);
  map.put(new Integer(100), new WeakReference<People>(p1));
  map.put(new Integer(101), new WeakReference<People>(p2));
  map.put(new Integer(1), new WeakReference<People>(p3));

  for(WeakReference<People> rp:map.values())
  {
   People p= rp.get();
   System.out.println("people:"+p);
  }
 }
}
class People{
 String name;
 int id;
 int age;
 public People(String name,int id)
 {
  this(name,id,0);
 }
 public People(String name,int id,int age)
 {
  this.name=name;
  this.id=id;
  this.age=age;
 }
 public String toString()
 {
  return id+name+age;
 }
 public boolean equals(Object o)
 {
  if(o==null)
   return false;
  if(!(o instanceof People))
   return false;
  People p=(People)o;
  boolean res=name.equals(p.name);
  if(res)
   System.out.println("name "+name+" is double");
  else
   System.out.println(name+" vS "+p.name);
  return res;
 }
 public int hashCode()
 {
  return name.hashCode();
 }
}

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91久久精品国产91久久性色| 91国偷自产一区二区三区的观看方式| 国产成人精品免高潮在线观看| 成人免费xxxxx在线观看| 国产精品嫩草影院久久久| 在线成人中文字幕| 亚洲欧美日韩高清| 日韩在线视频导航| 在线视频日本亚洲性| 亚洲va久久久噜噜噜久久天堂| 亚洲国产精久久久久久| 久久久久久久亚洲精品| 亚洲va久久久噜噜噜| 日韩精品免费视频| 国产午夜精品美女视频明星a级| 蜜月aⅴ免费一区二区三区| 这里只有精品视频在线| 国产精品视频色| 国产在线精品一区免费香蕉| 欧洲精品在线视频| 97国产精品免费视频| 日韩免费观看av| 欧美性黄网官网| 亚洲精品一区中文字幕乱码| 亚洲人成网站免费播放| 日本成人在线视频网址| 亚洲xxxxx| 亚洲视频免费一区| 中日韩美女免费视频网站在线观看| 国产成人av网址| 国产精品第8页| 国产精品三级美女白浆呻吟| 亚洲精品99久久久久| 91精品久久久久久久久久久久久| 精品久久香蕉国产线看观看gif| 在线观看免费高清视频97| 亚洲欧洲激情在线| 亚洲精品日产aⅴ| 成人黄色大片在线免费观看| 久久久久久久久久av| 国产做受高潮69| 日韩亚洲国产中文字幕| 国产精品热视频| 国产精品久久久久久久久久东京| 欧美精品videossex性护士| 成人欧美一区二区三区在线湿哒哒| 精品国产福利在线| 亚洲在线视频福利| 一区二区亚洲精品国产| 中文字幕亚洲综合久久筱田步美| 欧美另类老女人| www.亚洲天堂| 国产欧美久久久久久| 最近2019中文字幕大全第二页| 一区二区三区视频在线| 亚洲国产精品小视频| 中文字幕av一区中文字幕天堂| 欧美国产极速在线| 亚洲精选一区二区| 亚洲跨种族黑人xxx| 亚洲国产成人爱av在线播放| 国产成人精品免高潮在线观看| 久久精品影视伊人网| 国产成人精品a视频一区www| 久久精彩免费视频| 欧美黄色免费网站| 38少妇精品导航| 亚洲在线www| 欧美日产国产成人免费图片| 精品日韩中文字幕| 九九热99久久久国产盗摄| 国产精品444| 欧美日韩激情视频| 国产视频自拍一区| 久久久精品日本| 欧美精品免费在线| 国产精品麻豆va在线播放| 亚洲成av人影院在线观看| 成人免费看吃奶视频网站| 狠狠综合久久av一区二区小说| 欧美精品一本久久男人的天堂| 久久国产精品99国产精| 日本成人免费在线| 国产欧美精品xxxx另类| 日本精品久久久久久久| 欧美性在线视频| 成人精品一区二区三区电影黑人| 深夜福利一区二区| 久久人人爽人人爽人人片av高清| 日韩女在线观看| 国产在线精品播放| 日韩在线欧美在线| 8090成年在线看片午夜| 亚洲影院在线看| 久久久久成人精品| 国产一区二区丝袜高跟鞋图片| 欧美人与性动交| 国内精品400部情侣激情| 亚洲国产精品久久91精品| 在线视频欧美性高潮| 91美女福利视频高清| 亚洲日本中文字幕免费在线不卡| 欧美日韩国产成人在线| 国产精品嫩草影院一区二区| 国产欧美一区二区三区视频| 久久久久久有精品国产| 国产男女猛烈无遮挡91| 亚洲无线码在线一区观看| 国产日本欧美视频| 欧美裸身视频免费观看| 久久亚洲影音av资源网| 中文字幕一精品亚洲无线一区| 日韩电影大片中文字幕| 精品亚洲一区二区三区在线观看| 精品美女久久久久久免费| 国产精品毛片a∨一区二区三区|国| 两个人的视频www国产精品| 国产精品私拍pans大尺度在线| 国产精品久久久久久久app| 中文字幕亚洲情99在线| 亚洲精品二三区| 亚洲欧洲午夜一线一品| 中文字幕日韩有码| 国产欧美日韩最新| 国产一区二区免费| 操91在线视频| 中国china体内裑精亚洲片| 久久免费视频这里只有精品| 久久久www成人免费精品| 日韩综合中文字幕| 欧美日韩成人免费| 久久久久久久久爱| 91色琪琪电影亚洲精品久久| 国产午夜精品视频免费不卡69堂| 日韩黄在线观看| 国产日韩在线视频| 欧美黄色片视频| 有码中文亚洲精品| 北条麻妃99精品青青久久| 91人成网站www| 成人午夜激情网| 亚洲电影免费观看高清完整版| 4k岛国日韩精品**专区| 九九精品视频在线观看| 欧美在线视频在线播放完整版免费观看| 免费av一区二区| 国产精品国内视频| 亚洲一区二区久久久| 欧洲成人免费aa| 日韩中文在线中文网在线观看| 毛片精品免费在线观看| 在线观看欧美成人| 51久久精品夜色国产麻豆| 欧美精品一区在线播放| 日韩av在线直播| 欧美国产日韩一区二区三区| 亚洲少妇中文在线| 91高清在线免费观看| 成人中文字幕在线观看| 色偷偷88888欧美精品久久久| 久久中文字幕一区| 亚洲自拍偷拍区| 亚洲日本aⅴ片在线观看香蕉| 欧美高清不卡在线|