First of all I would like to clarify my understanding of the WeakReference
as the following question depends on the same.
static void test() {
Person p = new Person();
WeakReference<Person> person = new WeakReference<>(p);
p = null;
System.gc();
System.out.println(person.get());
System.out.println(person);
}
static class Person {
String name;
}
static class PersonMetadata {
String someData;
public PersonMetadata(String met) {
someData = met;
}
}
The output of the above code is
null
java.lang.ref.WeakReference@7852e922
Which means that although there is the actual person object is garbage collected once a GC runs, there is an object of WeakReference<Person>
class is there in the memory which does not point to anything at this point.
Now considering the above understanding true, I am confused about how does WeakHashMap<K,V>
works. In the below code
public static void main(String[] args) {
Person p = new Person();
p.name = "John";
WeakHashMap<Person, PersonMetadata> map = new WeakHashMap<>();
PersonMetadata meta = new PersonMetadata("Geek");
map.put(p, meta);
p = null;
System.gc();
if (map.values().contains(meta)) {
System.out.println("Value present");
} else {
System.out.println("Value gone");
}
}
static class Person {
String name;
}
static class PersonMetadata {
String someData;
public PersonMetadata(String met) {
someData = met;
}
}
OUTPUT: Value gone
Now the the question is as it is said that the key in WeakHashMap<K,V>
is an weak reference which means that in the above code when p
becomes null
the actual object can be garbage collected as there is no more strong reference to the object, but how does the and the value which is an object of PersonMetadata
class is getting garbage collected as the first code proves that object of WeakReference
class is not garbage collected even though the actual object is collected.
You are misunderstanding the situation. When
map.values().contains(meta)
, or shortmap.containsValue(meta)
returnsfalse
, it doesn’t imply thatmeta
has been garbage collected. In fact, you are holding a reference to the object inmeta
and even passing that reference to thecontains
method which may invokeequals
on it. So how could that object be garbage collected?The response only tells you that there is no association from one of the map’s keys to that object and since the only key has been garbage collected, that’s the correct answer. Alternatively, you could just have asked
map.isEmpty()
to check for the presence of the association.This is what the
WeakHashMap
provides:The removal of the entry is not instantaneous. It relies on enqueuing of the
WeakReference
into aReferenceQueue
, which is then polled internally when you make the next query, likecontainsValue
or evensize()
. E.g. if I change your program to:It occasionally prints “Value present” despite the key
Person
instance provenly has been garbage collected at this point. As said above, this is about the map’s internal cleanup, not about thePersonMetadata
instance to which we’re holding a strong reference inmeta
anyway.Making
PersonMetadata
eligible to garbage collection is an entirely different thing. As said, theWeakReference
does an internal cleanup whenever we call a method an it. If we don’t, there will be no cleanup and hence, still a strong reference, even if the key has been garbage collected. Consider:Which will print
demonstrating how the
WeakHashMap
holds a strong reference to the value of an already collected key until we eventually invoke a method on it, to give it a chance to perform its internal cleanup.The value finally gets collected when neither, the
WeakHashMap
nor our method, hold a reference on it. When we remove themeta = null;
statement, the map still will be empty at the end (after its internal cleanup), but the value won’t be collected.It’s important to keep in mind that these code examples are for demonstration purposes and touch implementation specific behavior, most notably, that a
main
method usually runs unoptimized. Formally, local variables are not required to prevent garbage collection if the referent is otherwise unused, a point which has relevance in practice when methods have been optimized.