WeakHashMap的使用不慎導(dǎo)致內(nèi)存溢出分析

字號(hào):

目前社區(qū)中有幾個(gè)應(yīng)用使用了類似Locker的代碼,基本上都是從消息系統(tǒng)引擎中提取出來的,的區(qū)別在于消息中使用的Locker中的id的類型為long,而id在作為鍵被put進(jìn)Map時(shí)被JVM自動(dòng)轉(zhuǎn)換成了Long,因此避免了 WeakHashMap中的鍵被值所引用。而如果使用String作為id則會(huì)因?yàn)镸ap中的值引用了自己的鍵,導(dǎo)致JVM無法根據(jù)鍵是否還被引用而清除 WeakHashMap中的entry??赏ㄟ^下面的測試代碼,清楚的觀察到結(jié)果。
    public class Locker {
    private static WeakHashMap lockerMap = new WeakHashMap();
    private final String id;
    private Locker(String id) {
    this.id= id;
    }
    public synchronized static Locker acquire(String id) {
    Locker locker = lockerMap.get(key);
    if (locker == null) {
    locker = new Locker(id);
    lockerMap.put(id, locker); //問題代碼,導(dǎo)致了entry.key == entry.value.id
    //lockerMap.put(new String(id), locker); //這是一種修改方式,保證了WeakHashMap中的key,沒有被value直接或間接所引用
    }
    return locker;
    }
    public String getId() {
    return this.id;
    }
    public static int getSize() {
    return lockerMap.size();
    }
    }
    public class LockerTest extends TestCase {
    public void testLocker() {
    for (int i = 0; i < 10000000; i++) {
    Locker.acquire("abc" + i);
    if (i % 10000 == 0) {
    System.gc();
    System.out.println(Locker.getSize()); //輸出垃圾回收后的Map的Size
    }
    }
    }
    }