3

这可能是预期的行为,但我找不到任何这样说的文档。我正在使用番石榴14.0.1。在下面的示例中,映射中没有强引用键的条目被删除,这是我所期望的,但是映射的大小不同步。

在第一次检查中,大小和计数都是5。但是,在第二次检查中,大小报告为5,但计数为0。为什么第二次检查实际上没有地图大小时报告地图大小为5地图中的条目?

import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class MapSizeCheck {
    public static void main(String[] args) {
        keepReferencesAndCheckSize();
        System.out.println();
        discardReferencesAndCheckSize();
    }

    private static void keepReferencesAndCheckSize() {
        Map<Object,Object> map = new MapMaker().weakKeys().makeMap();
        List<Object> refs = Lists.newArrayList();

        for(int i=0;i<5;i++) {
            Object key = new Object();
            Object value = new Object();

            map.put(key, value);
            refs.add(key); // Hold a strong reference to the key.
        }

        System.gc();

        int size = map.size();
        int count = 0;

        Iterator<Object> it = map.keySet().iterator();
        while(it.hasNext()) {
            count++;
            it.next();
        }

        System.out.println("Size  : " + size);
        System.out.println("Count : " + count);
    }

    private static void discardReferencesAndCheckSize() {
        Map<Object,Object> map = new MapMaker().weakKeys().makeMap();

        for(int i=0;i<5;i++) {
            Object key = new Object();
            Object value = new Object();

            map.put(key, value);
        }

        System.gc();

        int size = map.size();
        int count = 0;

        Iterator<Object> it = map.keySet().iterator();
        while(it.hasNext()) {
            count++;
            it.next();
        }

        System.out.println("Size  : " + size);
        System.out.println("Count : " + count);
    }
}
4

1 回答 1

5

这是预期的行为,但在MapMaker's 文档中并没有尽可能明确。但是,它与CacheBuilder's docs一致:

如果请求了weakKeys、weakValues 或softValues,则缓存中存在的键或值可能会被垃圾收集器回收。在每次缓存修改、偶尔的缓存访问或调用 Cache.cleanUp() 时,可能会从缓存中删除具有回收键或值的条目;此类条目可能会计入 Cache.size(),但对于读取或写入操作将永远不可见。

...以及JDK自己的WeakHashMap

public int size()

返回此映射中键值映射的数量。此结果是一个快照,可能不会反映在下次尝试访问之前将被删除的未处理条目,因为它们不再被引用。

于 2013-07-09T23:09:23.847 回答