为什么当使用弱键时,Guava的MapMaker报告的地图大小不正确?

时间:2022-11-10 20:46:03

It's possible this is the expected behavior, but I can't find any documentation that says so. I'm using Guava 14.0.1. In the below example, entries in the map that don't have a strong reference to the key get removed, which is what I expect, but the size of the map gets out of sync.

这可能是预期的行为,但我找不到任何说明的文档。我正在使用Guava 14.0.1。在下面的示例中,地图中没有对该键的强引用的条目被删除,这是我所期望的,但是地图的大小不同步。

In the first check, both the size and count are 5. However, in the second check the size is reported as 5, but the count is 0. Why does the second check report the map size as 5 when there aren't actually any entries in the map?

在第一次检查中,大小和计数都是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);
    }
}

1 个解决方案

#1


5  

This is expected behavior, but it's not made as explicit in MapMaker's docs as it could be. It is, however, consistent with CacheBuilder's docs:

这是预期的行为,但它并没有像MapMaker的文档那样明确。但是,它与CacheBuilder的文档一致:

If weakKeys, weakValues, or softValues are requested, it is possible for a key or value present in the cache to be reclaimed by the garbage collector. Entries with reclaimed keys or values may be removed from the cache on each cache modification, on occasional cache accesses, or on calls to Cache.cleanUp(); such entries may be counted in Cache.size(), but will never be visible to read or write operations.

如果请求weakKeys,weakValues或softValues,则垃圾收集器可以回收缓存中存在的密钥或值。具有回收键或值的条目可以在每次高速缓存修改,偶尔的高速缓存访​​问或调用Cache.cleanUp()时从高速缓存中删除;这些条目可以在Cache.size()中计算,但对于读取或写入操作永远不可见。

...as well as the JDK's own WeakHashMap:

...以及JDK自己的WeakHashMap:

public int size()

public int size()

Returns the number of key-value mappings in this map. This result is a snapshot, and may not reflect unprocessed entries that will be removed before next attempted access because they are no longer referenced.

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

#1


5  

This is expected behavior, but it's not made as explicit in MapMaker's docs as it could be. It is, however, consistent with CacheBuilder's docs:

这是预期的行为,但它并没有像MapMaker的文档那样明确。但是,它与CacheBuilder的文档一致:

If weakKeys, weakValues, or softValues are requested, it is possible for a key or value present in the cache to be reclaimed by the garbage collector. Entries with reclaimed keys or values may be removed from the cache on each cache modification, on occasional cache accesses, or on calls to Cache.cleanUp(); such entries may be counted in Cache.size(), but will never be visible to read or write operations.

如果请求weakKeys,weakValues或softValues,则垃圾收集器可以回收缓存中存在的密钥或值。具有回收键或值的条目可以在每次高速缓存修改,偶尔的高速缓存访​​问或调用Cache.cleanUp()时从高速缓存中删除;这些条目可以在Cache.size()中计算,但对于读取或写入操作永远不可见。

...as well as the JDK's own WeakHashMap:

...以及JDK自己的WeakHashMap:

public int size()

public int size()

Returns the number of key-value mappings in this map. This result is a snapshot, and may not reflect unprocessed entries that will be removed before next attempted access because they are no longer referenced.

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