2

我正在使用一个大型(数百万)哈希图在 Java 上工作,该哈希图实际上是用 10.000.000 的容量和 0.75 的负载因子构建的,它用于缓存一些值

因为缓存的值随着时间的推移变得无用(不再访问)但我无法删除无用的值,而我想在缓存的性能开始下降时完全清空缓存。我怎样才能决定什么时候这样做是好的?

例如,有 1000 万个容量和 0.75,当它达到 750 万个元素时我应该清空它吗?因为我尝试了各种阈值,但我想要一个分析阈值。

我已经测试了这样一个事实,即当它非常满时将其清空可以提高性能(擦除后的前 2-3 次算法迭代只是将其填满,然后它开始比擦除前更快地运行)

编辑:附加信息

hashmap 有 long as 键和 float 作为值。它包含缓存的内容相关性,因为它是标签向量的点积,我想缓存它们(以提高性能)。

所以基本上我所做的是long使用 2 个内容的哈希码计算一个密钥:

static private long computeKey(Object o1, Object o2)
{
    int h1 = o1.hashCode();
    int h2 = o2.hashCode();

    if (h1 < h2)
    {
        int swap = h1;
        h1 = h2;
        h2 = swap;
    }

    return ((long)h1) << 32 | h2;
}

并使用它来检索存储的值。发生的情况是,由于它是一个层次聚类,内容被合并,不再需要它们与其他内容的相关值。这就是为什么我想不时擦除哈希图,以避免由于其中无用的值而退化。

使用 aWeakHashMap也会在仍然需要数据时意外地清除数据。我无法控制它。

谢谢

4

3 回答 3

5

Why not use an LRU Cache? From Java's LinkedHashMap documentation:

A special constructor is provided to create a linked hash map whose order of iteration is the order in which its entries were last accessed, from least-recently accessed to most-recently (access-order). This kind of map is well-suited to building LRU caches. Invoking the put or get method results in an access to the corresponding entry (assuming it exists after the invocation completes). The putAll method generates one entry access for each mapping in the specified map, in the order that key-value mappings are provided by the specified map's entry set iterator. No other methods generate entry accesses. In particular, operations on collection-views do not affect the order of iteration of the backing map.

So basically, every once in a while as your map gets too big, just delete the first x values that the iterator gives you.

See documentation for removeEldestEntry to have this done for you automatically.

Here is code that demonstrates:

 public static void main(String[] args) {
    class CacheMap extends LinkedHashMap{
      private int maxCapacity;
      public CacheMap(int initialCapacity, int maxCapacity) {
        super(initialCapacity, 0.75f, true);
        this.maxCapacity = maxCapacity;
      }

      @Override
      protected boolean removeEldestEntry(Map.Entry eldest) {
        return size()>maxCapacity;
      }
    }

    int[] popular = {1,2,3,4,5};
    CacheMap myCache = new CacheMap(5, 10);
    for (int i=0; i<100; i++){
      myCache.put(i,i);
      for (int p : popular) {
        myCache.get(p);
      }
    }

    System.out.println(myCache.toString()); 
    //{95=95, 96=96, 97=97, 98=98, 99=99, 1=1, 2=2, 3=3, 4=4, 5=5}
  }
于 2010-03-11T16:54:22.087 回答
2

你调查过WeakHashMaps吗?垃圾收集器可以确定何时删除东西,它可能会给你一个可接受的替代品,而不是你自己编写一些东西。

这篇文章有更多有用的信息。

于 2010-03-11T16:34:51.337 回答
2

您可能希望使用 Google Collections 的MapMaker制作带有软引用和特定超时的地图。

软引用“由垃圾收集器根据内存需求自行清除”。

例子:

ConcurrentMap<Long, ValueTypeHere> cacheMap = new MapMaker()
    .concurrencyLevel(32)
    .softValues()
    .expiration(30, TimeUnit.MINUTES)
    .makeMap();

如果你想让它的键像 WeakHashMap 中的键一样,你也可以指定weakKeys。

于 2010-03-11T16:59:06.143 回答