我正在使用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,它们可能会过早收回,或者它们可能永远不会被收回,直到它们填满我的堆。
我有什么方法可以监控地图的大小并根据它进行约束?
答案 0 :(得分:3)
如果软/弱引用不可用,那么我会看到2个(非平凡的)选项:
1)使用Java检测来检查添加到地图中的项目的实际大小。检测接口提供了对象的"shallow" size,您将需要更多代码来探索引用(并避免计算重复项!)。 Here是一种计算一个对象的深度大小的解决方案。
2)使用JMX跟踪GC之后的堆大小,并在达到某个危险阈值时更改映射行为。请参阅MemoryMXBean javadoc中的“通知”部分。
答案 1 :(得分:2)
地图本身仅包含固定大小的条目,其中包含对地图中“包含”的实际对象的引用。您需要覆盖所有地图变异方法(即put()
,复制构造函数等)以跟踪从地图引用的对象的大小(您甚至可以确定Java对象占用多少内存? )。然后考虑添加到缓存中的对象本身可能包含对其他对象和/或集合的引用。你有多深?
答案 2 :(得分:1)
正如其他人所提到的,您可以使用代理程序检测来执行此操作。 SizeOf项目为此方法提供了一个方便的实用程序。这可以与ConcrrentLinkedHashMap的加权值概念一起使用,其中Weigher确定值消耗的容量单位。这使得缓存能够正确处理集合或内存限制,以及传统的最大条目数限制。
如果你希望绑定到堆,那么有一个早期版本的ConcurrentLinkedHashMap的分支可以执行此操作。这保留了原始的Apache许可证,因此它可以根据您的需要进行调整,因为它与Voldemort打包在一起。
http://sizeof.sourceforge.net/
答案 3 :(得分:0)
您可以打包Map
实施并在put
和putAll
方法中强制执行此尺寸。