Reputation: 351
I'm trying to trace a memory leak in Java. Does this snippet actually prevent the garbage collection.
SortedMap<K,V> cache = ... /* some sorted map */
// and later in a loop, I do
cache = cache.tailMap(someIndex); // does this prevent gc of elements < someIndex
The elements < someIndex are not available anymore in follow-up code. Are they also garbage collected? I'm running into a java.lang.OutOfMemoryError
after a while, not sure if this is the reason...
I cannot create a temporary map and reassign like
tmp = new SortedMap<K,V>();
tmp.putAll(cache.tailMap(someIndex));
cache.clear();
cache = tmp; // this breaks the "final"
as I need the original cache
object, because it's final. How do I schedule those elements < someIndex for GC, i.e. do I really need to call remove()
in a loop? Is there a better way than this?
// "TreeSet" to make sure the keys are ordered
Iterator<K> it = new TreeSet<K>(cache.keySet()).iterator();
while (it.hasNext())
{
if (it.next() < someIndex) it.remove();
else break;
}
Edit: SOLVED
Actually the above was not working as expected. Of couse, it was necessary to remove the elements in the map, not within the keyset!
// "TreeSet" to make sure the keys are ordered
Iterator<K> it = new TreeSet<K>(cache.keySet()).iterator();
while (it.hasNext())
{
K key = it.next();
if (key < someIndex) cache.remove(key); // not it.remove();
else break;
}
Edit 2
Most elegant, as suggested by Louis Wassermann below, this is what I was originally after:
cache.headMap(someIndex).clear();
No iterator, no key set, no need to loop - beautiful! Thank you!
Upvotes: 0
Views: 256
Reputation: 269707
Yes, tailMap()
creates a view that retains a reference to the parent object. You need to clean up that parent object.
SortedMap<K,V> cache = ... /* some sorted map */
// and later in a loop, DO THIS INSTEAD:
cache.headMap(someIndex, false).clear();
This change through the headMap()
view removes unnecessary entries from the underlying cache
map.
Upvotes: 0
Reputation: 1523
Javadoc (https://docs.oracle.com/javase/7/docs/api/java/util/SortedMap.html#tailMap(K)) is quite clear : the tailMap()
method return a view of the map, backed by the original map. Elements are not removed from the original map, and the original map is still reachable as the new map has a reference on it.
In your case, you must call remove to effectively make objets garbageable.
Upvotes: 1
Reputation: 23329
If cache
is reachable from a GC root, then the map and its keys will not be eligible for garbage collection. What you looking for is a key eviction policy or data-structure.
Guava Cache might be a good option.
Upvotes: 1