代码之家  ›  专栏  ›  技术社区  ›  Neil Traft

我可以根据哈希图占用的内存量来约束它吗?

  •  3
  • Neil Traft  · 技术社区  · 14 年前

    我正在使用 LinkedHashMap 根据找到的说明 here . 我使用以下代码:

    public class Cache extends LinkedHashMap {
      private final int capacity;
    
      public Cache(int capacity) {
        super(capacity + 1, 1.1f, true);
        this.capacity = capacity;
      }
    
      protected boolean removeEldestEntry(Entry eldest) {
        return size() > capacity;
      }
    }
    

    这很容易。然而,它只是在地图上施加了一个固定的大小。我在一个非常小的堆上运行,根据缓存对象的大小和我选择的容量,这可能仍然会耗尽内存。这些物体是任意的,所以我无法估计它们有多大。我不想依赖 SoftReferences 修剪缓存是因为这些缓存的清理方式不可靠;它从vm更改为vm,它们可能太早被回收,或者在填满我的堆之前永远不会被回收。

    有没有什么方法可以让我监控地图的大小并基于它进行约束?

    4 回复  |  直到 14 年前
        1
  •  3
  •   Eyal Schneider    14 年前

    如果软/弱引用是不可能的,那么我会看到两个(非常重要的)选项:

    1)使用Java工具来检查添加到映射中的项的实际大小。仪表接口提供 "shallow" size 对于一个对象,您将需要更多的代码来探索引用(并避免计算重复项!). Here 是计算一个对象的深度大小的解决方案。

    2)使用jmx跟踪gcs之后的堆大小,并在达到某个危险阈值时更改映射行为。请参阅中的“通知”部分 MemoryMXBean javadoc .

        2
  •  2
  •   Jim Garrison    14 年前

    地图本身只包含固定大小的条目,其中包含对地图中“包含”的实际对象的引用。您将需要覆盖所有映射转换方法(即 put() 跟踪映射中引用的对象的大小(甚至可以确定Java对象占用了多少内存)?。然后考虑添加到缓存中的对象本身可能包含对其他对象和/或集合的引用。你有多深?

    看一看 http://www.javapractices.com/topic/TopicAction.do?Id=83

        3
  •  1
  •   Ben Manes    14 年前

    正如其他人提到的,您可以使用代理检测来完成这项工作。sizeof项目为这种方法提供了一个方便的实用程序。这可以与ConcurrentLinkedHashMap的加权值概念一起使用,在加权值概念中,加权器决定一个值消耗多少容量单位。这样,除了传统的最大条目数约束之外,缓存还可以正确处理集合或内存限制。

    如果您希望被堆绑定,那么有一个concurrentlinkedHashMap早期版本的分叉可以做到这一点。它保留了原始版本的Apache许可证,因此可以根据您的需要进行调整,因为它与伏地魔打包在一起。

    http://sizeof.sourceforge.net/

    http://code.google.com/p/concurrentlinkedhashmap/

    http://github.com/Omega1/voldemort/blob/master/src/java/voldemort/store/memory/ConcurrentLinkedHashMap.java

        4
  •  0
  •   Steve Kuo    14 年前

    你可以包装一个 Map put putAll 方法。