I am implementing a simple cache using LinkedHashMap based on the instructions found here. I use the following code:
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;
}
}
This is very easy. However, it simply imposes a fixed size on the map. I am running on a very small heap and depending on the size of the cached objects and my chosen capacity this could still run out of memory. The objects are arbitrary and so I can’t estimate how big they might be. I don’t want to depend on SoftReferences to prune the cache because the way those are cleaned up is unreliable; it changes from VM to VM, and they might either get reclaimed too soon, or they might never get reclaimed until they fill up my heap.
Is there any way for me to monitor the size of the map and constrain based on that?
If soft/weak references are out of the question, then I see 2 (non-trivial) options:
1) Use Java instrumentation to check the actual size of the items added to the map. The instrumentation interface provides the “shallow” size of an object, and you will need more code to explore the references (and avoid counting duplicates!). Here is a solution that calculates the deep size of one object.
2) Use JMX to track the heap size after GCs, and change the map behavior when some dangerous threshold is being reached. See “notifications” section in MemoryMXBean javadoc.