通过有效地查找最后使用的元素来保持缓存(映射)小

时间:2016-03-28 01:20:18

标签: algorithm caching data-structures

我有一个java应用程序,它提供大平铺图像的重采样区域。

由于连续区域查询通常彼此接近,因此将图像切片缓存在哈希映射中是有意义的。现在我想让这个缓存无限期地增长。

为了不失去性能,我需要一种O(1)/ O(logN)方法来查找最长时间未被访问的地图元素。有没有办法做到这一点,它与仅从缓存中删除随机元素相比如何?

堆或bst允许我保持对最后一次访问的列表进行排序,但更新其中一次访问的最后一次访问将需要线性时间。

以下是我目前使用的代码的摘录:

insertBefore()

这不是最佳选择,因为最久前加载的图像可能刚刚被访问过。

2 个答案:

答案 0 :(得分:1)

LinkedHashMap与Collections.synchronizedMap(linkedHashMap)一起完成了这个伎俩。 LinkedHashMap的removeEldestEntry方法允许定义何时删除最后访问的条目的条件。

final int MAX_BUF_SIZE = 1000;

Map<Point, BufferedImage> loadedImages = new LinkedHashMap(MAX_BUF_SIZE + 1, .75F, true) {

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

int getRGB(double tileX, double tileY) {
    Point point = new Point((int) tileX, (int) tileY);
    if (!loadedImages.containsKey(point)) {
        loadedImages.put(point, ImageIO.read(new File("R:\\tiles\\22\\" + point.y + "_" + point.x + ".jpg")));
    }

    BufferedImage img = loadedImages.get(point);
    //do stuff with img..
}

答案 1 :(得分:0)

将LinkedHashMap用作LRUCache - 简单示例:

public class LRULinkedHashMap extends LinkedHashMap<Integer, String> {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private int capacity;

    public LRULinkedHashMap(int capacity) {
        // initialise the capacity, and when to 'double' the capacity (75% of capacity) and 
        // 'true' if the ordering should be done based on the last
        // access (from least-recently accessed to most-recently accessed) 
        super(capacity, 0.75f, true);
        this.capacity = capacity;
    }


    /**
     * Returns true if this map should remove its eldest entry. 
     * This method is invoked by put and putAll after inserting a new entry into the map. 
     * It provides the implementor with the opportunity to remove the eldest entry each 
     * time a new one is added. This is useful if the map represents a cache: it allows 
     * the map to reduce memory consumption by deleting stale entries.
     */
    @Override
    protected boolean removeEldestEntry(Entry<Integer, String> eldest) {
        // this will return true and remove the eldest entry every time the size of the map
        // is bigger than the capacity - the size() will never go beyond double the capacity
        // (it will double automatically when it hits 75% of original capacity) as this ensures
        // any 'put' entry over the capacity is removes the eldest object 
        return size() > this.capacity;
    }



    public static void main(String[] args) {
        // TODO Auto-generated method stub

        // Last Recently Used LinkedHashMap Cache
        LRULinkedHashMap cache = new LRULinkedHashMap(6);

        // put some objects into the map
        cache.put(1, "one");
        System.out.println(cache);
        cache.put(2, "two");
        System.out.println(cache);
        cache.put(3, "three");
        System.out.println(cache);
        cache.put(4, "four");
        System.out.println(cache);
        cache.put(5, "five");
        System.out.println(cache);
        cache.put(6, "six"); // capacity (6) reached
        System.out.println(cache + "  <-- Capacity Reached");
        cache.put(7, "seven"); // 1 is removed - eldest
        System.out.println(cache + "  <-- 1 removed");
        cache.put(8, "eight"); // 2 is removed - next eldest
        // access an object before it is removed
        System.out.println(cache + "  <-- 2 Removed");
        cache.get(4); // 4 retrieved placed after 8 - nothing removed (we've only changed the order, not put anything into the map)
        System.out.println(cache + "  <-- '4' Retrieved, access order changed only");
        cache.put(9, "nine"); // 3 is removed - next eldest (4 was retrieved!) 
        System.out.println(cache + "  <-- 3 Removed");
        cache.put(10, "ten"); // 5 removed - next eldest
        // first item is always the eldest - will be next to go if item retrieved or put in map
        System.out.println(cache + "  <-- 5 Removed");

    }

}