什么时候垃圾列表内容避免性能降解?
-
19-09-2019 - |
题
我在Java上使用一个较大(数百万)的hashmap,实际上以10.000.000的容量和0.75的负载系数构建,用于缓存一些值
由于缓存值随着时间而变得毫无用处(不再访问),但是在途中,我无法在其性能开始降低时完全清空该缓存的途径。我该如何决定何时做事?
例如,当它达到7500万个元素时,我应该将100万个容量和.75倒入吗?因为我尝试了各种阈值值,但我想拥有一个分析值。
我已经测试了以下事实:当它完全饱满后,它是一种提高性能(在擦除后首先2-3算法迭代只是填充它,然后它开始运行的速度比擦拭之前的速度要快得多)
编辑:其他信息
哈希图的键和浮点很长。它包含内容的缓存相关性,因为它是我想缓存它们的标签矢量的点产物(以提高性能)。
因此,基本上我要做的是计算 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;
}
并使用它来检索存储的值。发生的事情是,由于它是一个层次的群集内容,并且不再需要其与其他内容的相关值。这就是为什么我想不时擦除哈希图,以免由于其中的无用值而降级。
用一个 WeakHashMap
当仍然需要时,也将不可预测地消除数据。我无法控制它。
谢谢
解决方案
为什么不使用LRU缓存?来自Java的LinkedHashmap文档:
提供了一个特殊的构造函数来创建一个链接的哈希地图,其迭代顺序是最后访问其条目的顺序,从最少访问到最清晰的(访问订单)。这种地图非常适合构建LRU缓存。调用PUT或获得方法会导致对相应条目的访问(假设在调用完成后存在)。 Putall方法在指定地图中为每个映射生成一个条目访问,以指定地图的输入集迭代器提供键值映射的顺序。没有其他方法生成条目访问。特别是,收集视图的操作不会影响背映射的迭代顺序。
因此,基本上,随着地图的大小,每隔一段时间,只需删除迭代器给您的第一个X值即可。
请参阅文档 removeEldestEntry
为您自动完成此操作。
这是证明:
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}
}
其他提示
您可能想使用Google Collections' MAPMAKER 制作具有软引用和特定超时的地图。
软引用“由垃圾收集器酌情决定,以响应记忆需求。”
例子:
ConcurrentMap<Long, ValueTypeHere> cacheMap = new MapMaker()
.concurrencyLevel(32)
.softValues()
.expiration(30, TimeUnit.MINUTES)
.makeMap();
如果您想将其钥匙像弱的钥匙一样,则可以指定弱者。