Java固定内存映射

jub*_*ber 13 java caching dictionary memory-management fixed

是否有一个简单,高效的Map实现,允许地图使用内存限制.

我的用例是我想动态分配创建时可用的大部分内存,但我不希望OutOFMemoryError在将来的任何时候.基本上,我想使用这个地图作为缓存,但我想避免繁重的缓存实现,如EHCache.我的需求很简单(最多一个LRU算法)

我应该进一步澄清我的缓存中的对象是char[]或类似的原语,它们不会保存对其他对象的引用.

我可以为每个条目设置最大大小的上限.

pol*_*nts 10

您可以使用a LinkedHashMap来限制以下内容中的条目数Map:

removeEldestEntry(Map.Entry<K,V> eldest):true如果此映射应删除其最旧条目,则返回.在将新条目插入地图之后putputAll之后调用此方法.它为实现者提供了在每次添加新条目时删除最旧条目的机会.如果映射表示缓存,这将非常有用:它允许映射通过删除过时条目来减少内存消耗.

示例使用:此覆盖将允许地图增长到100个条目,然后在每次添加新条目时删除最旧的条目,保持100个条目的稳定状态.

private static final int MAX_ENTRIES = 100;

protected boolean removeEldestEntry(Map.Entry eldest) {
    return size() > MAX_ENTRIES;
}
Run Code Online (Sandbox Code Playgroud)

相关问题


mdm*_*dma 6

对于缓存,a SoftHashMap比a更合适WeakHashMap.当您想要保持与对象的关联时,通常使用WeakhashMap,只要该对象处于活动状态,但不会阻止它被回收.

相反,a SoftReference更密切地涉及内存分配.请参阅否SoftHashMap?有关差异的详细信息.

WeakHashMap通常也不合适,因为它具有围绕错误的缓存方式的关联 - 它使用弱键和硬值.也就是说,当垃圾收集器清除密钥时,密钥和值将从映射中删除.这通常不是您想要的缓存 - 其中键通常是轻量级标识符(例如字符串或其他一些简单的值类型) - 缓存通常操作使得在清除引用时回收键/值.

Commons Collections有一个ReferenceMap可以插入您希望用于键和值的引用类型的地方.对于对内存敏感的缓存,您可能会使用键的硬引用和值的软引用.

要获取给定数量的引用N的LRU语义,请维护从缓存中获取的最后N个条目的列表 - 当从缓存中检索条目时,将其添加到列表的头部(并且删除列表的尾部) .)为了确保不会占用太多内存,您可以创建一个软引用,并将其用作触发器,从列表末尾逐出百分比的条目.(并为下一个触发器创建一个新的软参考.)


jub*_*ber 0

谢谢你们的回复!

正如 jasonmp85 指出的那样,LinkedHashMap 有一个允许访问顺序的构造函数。当我查看 API 文档时,我错过了这一点。该实现看起来也相当高效(见下文)。结合每个条目的最大尺寸上限,这应该可以解决我的问题。

我还将仔细研究 SoftReference。仅供记录,Google Collections 似乎对 SoftKeys、SoftValues 和 Maps 有相当好的 API。

下面是 Java LikedHashMap 类的一个片段,展示了它们如何维护 LRU 行为。

    /**
     * Removes this entry from the linked list.
     */
    private void remove() {
        before.after = after;
        after.before = before;
    }

    /**
     * Inserts this entry before the specified existing entry in the list.
     */
    private void addBefore(Entry<K,V> existingEntry) {
        after  = existingEntry;
        before = existingEntry.before;
        before.after = this;
        after.before = this;
    }

    /**
     * This method is invoked by the superclass whenever the value
     * of a pre-existing entry is read by Map.get or modified by Map.set.
     * If the enclosing Map is access-ordered, it moves the entry
     * to the end of the list; otherwise, it does nothing.
     */
    void recordAccess(HashMap<K,V> m) {
        LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
        if (lm.accessOrder) {
            lm.modCount++;
            remove();
            addBefore(lm.header);
        }
Run Code Online (Sandbox Code Playgroud)