2010-07-28 73 views
3

我正在根据here的说明使用LinkedHashMap来实现一个简单的缓存。我使用下面的代码:我可以通过它占用的内存量限制HashMap吗?

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来修剪缓存,因为那些被清理的方式是不可靠的;它会从虚拟机变成虚拟机,他们可能会很快得到回收,或者他们可能永远不会回收,直到他们填满我的堆。

有没有什么办法让我监视地图的大小和限制?

回答

3

如果软/弱引用是出了问题,然后我看到2(非平凡)选项:

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

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

0

您可以打包Map实现并在putputAll方法中执行大小。

+1

我很困惑,我将如何评估传入对象的大小?我问的是实际占用的堆空间字节数,而不是对象数。 – 2010-07-28 20:41:24

2

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

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

+0

我想这基本上是我问 - 是否有可能确定任意对象的浅和/或保留大小?我知道,这是一个荒谬的问题。 :-P – 2010-07-28 20:43:02

+0

我添加了一个链接到我在Google搜索“java大小的对象”中找到的页面。该结果页面上有许多有趣的链接。 – 2010-07-28 20:55:14

1

正如其他人所说的,您可以使用代理工具来执行此操作。 SizeOf项目为这种方法提供了一个方便的工具。这可以与ConcrrentLinkedHashMap的加权值概念一起使用,其中Weigher确定一个值消耗多少个单位的容量。这使得缓存除了传统的最大条目数限制之外,还可以正确处理集合或内存限制。

如果你希望受到堆的束缚,那么就有一个早期版本的ConcurrentLinkedHashMap的fork来做这件事。这保留了原版的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

相关问题