我可以通过占用的内存量来约束HashMap吗?

时间:2010-07-28 20:17:08

标签: java memory-management caching

我正在使用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 个答案:

答案 0 :(得分:3)

如果软/弱引用不可用,那么我会看到2个(非平凡的)选项:

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

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

答案 1 :(得分:2)

地图本身仅包含固定大小的条目,其中包含对地图中“包含”的实际对象的引用。您需要覆盖所有地图变异方法(即put(),复制构造函数等)以跟踪从地图引用的对象的大小(您甚至可以确定Java对象占用多少内存? )。然后考虑添加到缓存中的对象本身可能包含对其他对象和/或集合的引用。你有多深?

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

答案 2 :(得分:1)

正如其他人所提到的,您可以使用代理程序检测来执行此操作。 SizeOf项目为此方法提供了一个方便的实用程序。这可以与ConcrrentLinkedHashMap的加权值概念一起使用,其中Weigher确定值消耗的容量单位。这使得缓存能够正确处理集合或内存限制,以及传统的最大条目数限制。

如果你希望绑定到堆,那么有一个早期版本的ConcurrentLinkedHashMap的分支可以执行此操作。这保留了原始的Apache许可证,因此它可以根据您的需要进行调整,因为它与Voldemort打包在一起。

http://sizeof.sourceforge.net/

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

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

答案 3 :(得分:0)

您可以打包Map实施并在putputAll方法中强制执行此尺寸。