一直很想知道WeakHashMap的使用場景,想來想去隻能用在高速緩存中,而且緩存的資料還不是特别重要,因為key(key不存在被引用的時候)随時會被回收
是以研究了一下WeakHashMap的回收時機
呵呵,現在可以重視 String str = "abc" 跟 String Str = new String("abc") 的差別了,因為涉及到收回問題
String str = "abc" //這屬于編譯時生成的字面量,會放入運作時常量池,這個區域的收回條件非常苛刻,是以一般不會被回收,是以哪怕不存在引用,WeakHashMap的這個key也不容易被回收
String Str = new String("abc") //會放入堆記憶體,GC着重處理這個區
/**
*
* @author ZhenWeiLai
*
*/
public class TestWeakHashMap {
static WeakHashMap<String,String> map = new WeakHashMap<>();
//會被回收因為 map 的 key 用 new String 執行個體化了一個對象 儲存在堆裡,雖然是線程共享,但是并沒有任何引用指向這個key
/**
* 這裡補充一下,Java heap 是被所有線程共享的一塊記憶體區域
* 幾乎所有的對象執行個體都在這裡配置設定記憶體,這裡說幾乎,是因為随着JIT編譯器的發展與逃逸分析技術逐漸成熟
* 棧上配置設定,标量替換等優化技術将導緻一些微妙的變化發生,所有的對象都配置設定在堆上也漸漸變得不是那麼絕對
*/
static {
map.put(new String("a"),new String("abc"));
map.put(new String("b"),new String("abc"));
map.put(new String("c"),new String("abc"));
map.put(new String("d"),new String("abc"));
map.put(new String("e"),new String("abc"));
map.put(new String("f"),new String("abc"));
map.put(new String("g"),new String("abc"));
}
//會被回收
static WeakHashMap<String,String> map4 = new WeakHashMap<>();
static {
map4.put(new String("a"),"abc");
map4.put(new String("b"),"abc");
map4.put(new String("c"),"abc");
map4.put(new String("d"),"abc");
map4.put(new String("e"),"abc");
map4.put(new String("f"),"abc");
map4.put(new String("g"),"abc");
}
static WeakHashMap<String,String> map2 = new WeakHashMap<>();
//不會被收回,因為存在 方法區(以前也叫永久代,JAVA8已經不存在永久代) - 常量池
/**
* (Method Area 别名 Non-Heap) 與Java Heap 一樣,是各個線程共享的記憶體區域,
* 以前這個區域也叫作 永久代,因為幾乎不會被回收
* 它用于存儲已被虛拟機加載的類資訊,常量,靜态變量.即時編譯後的代碼等資料
*/
/**
* map2的key 是存在 運作時常量池,運作時常量池是 Method Area的一部分
* Java并不要求常量一定隻有在編譯期才能産生,運作期間也可能将新的常量放入池中,具有代表性的就是String的intern()方法
*/
static {
map2.put("a","abc");
map2.put("b","abc");
map2.put("c","abc");
map2.put("d","abc");
map2.put("e","abc");
map2.put("f","abc");
map2.put("g","abc");
}
public static void main(String[] args) throws InterruptedException {
while(true){
/**
* 解開注釋,map,map4的key将不會被回收
* 我了解為,在棧(也叫線程私有棧,或者工作記憶體)中,每個線程會将共享資料拷貝到棧頂進行運算,
* 這份資料其實是一個副本.(如果棧内部所包含的"局部變量"是引用,則僅僅是引用值在棧中,而且會占用一個引用本身的大小,具體的對象還是在堆當中,即對象本身的大小與棧空間的使用無關)
* 是以這個map存在一個引用,就不會去回收它的key
*/
// System.out.println("map:"+map.size());
// System.out.println("map2:"+map2.size());
// System.out.println("map4:"+map4.size());
//模拟被一個線程調用,然後休眠5秒,會随機被回收
new Thread(()->{
System.out.println("map:"+map.size());
System.out.println("map2:"+map2.size());
System.out.println("map4:"+map4.size());
System.out.println("-------------------");
}).start();
TimeUnit.SECONDS.sleep(5);
}
}
}