3

我正在尝试使用 LinkedHashMap 作为本地 FIFO 缓存解决方案,覆盖其 removeEldestEntry 方法以保持大小固定:

Map lhm = new LinkedHashMap(MAX_CACHE_SIZE + 1, .75F, false) {
   protected boolean removeEldestEntry(Map.Entry eldest) {
      return size() > MAX_CACHE_SIZE;
   }
};

但是当我不断向映射监视进程内存添加新条目时,我发现它一直在增长,直到使用最大虚拟机内存,尽管映射大小没有增加。

是设计使然吗?如果旧值被丢弃并且地图的大小受到限制,为什么它需要更多内存?

更新:根据要求,我附上了完整的代码:

@Test
public void mapMemory() {
    final int MAX_CACHE_SIZE = (int) 1E3;
    Map lhm = new LinkedHashMap(MAX_CACHE_SIZE + 1, 1F, false) {
       protected boolean removeEldestEntry(Map.Entry eldest) {
          return size() > MAX_CACHE_SIZE;
       }
    };

    for (long i = 0; i < 1E10; i++) {
        lhm.put("key_" + i, "VALUE");
    }
}
4

3 回答 3

2

一篇博客文章解释了多线程上下文中 LinkedHashMap 的内存泄漏问题

https://hoangx281283.wordpress.com/2012/11/18/wrong-use-of-linkedhashmap-causes-memory-leak/

于 2014-04-08T03:35:23.167 回答
0

构造函数中的第二个参数定义 loadFactor,乘以第一个参数(地图大小),它会为您提供触发地图调整大小的值(大小)。因此,在您的情况下,您应该(可能)使用 loadFactor = 1。

编辑:
您的内存泄漏是由您没有向我们展示的东西引起的,您上面的代码永远不会导致内存泄漏。
检查您可能保留对旧值/对象的引用的位置。地图本身不会导致内存泄漏 - 如果它确实使用地图的所有系统(并且有很多)每隔几个小时就会崩溃一次。

于 2013-10-28T11:25:14.707 回答
0

如果您需要随机访问集合的内容,那么它并不是真正的 FIFO。

应该注意的是,集合不存储对象,它们存储对对象的引用,这是一个重要的区别。将同一个对象存储在 2 个不同的集合中不会有显着的内存开销,所以也许你最好的解决方案是将同一个对象存储到队列和映射中,当你需要 FIFO 行为时使用队列,当你需要随机访问时使用映射.

但是,您必须记住在完成后从两个集合中删除该对象,否则它不会被 GC 处理。

于 2013-10-28T12:54:39.473 回答