I am understanding the concept of WeakhashMap. String literal and String object made it difficult to understand.
Following is the code:
package com.lnt.StringBuf;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
public class Test1 {
public static void main(String[] args) {
Map w = new WeakHashMap();
Map h = new HashMap<>();
String hkey = new String("hashkey");
String wkey = new String("weakkey");
/* String hkey = "hashkey";
String wkey = "weakkey";*/
h.put(hkey, 1);
w.put(wkey, 1);
System.gc();
System.out.println("Before");
System.out.println("hashmap size: " + h.size());
System.out.println("weakmap size: " + w.size());
System.out.println("Hashmap value: " + h.get("hashkey") + "\t"
+ "weakmap value: " + w.get("weakkey"));
hkey = null;
wkey = null;
System.gc();
System.out.println(hkey+" "+wkey);
System.out.println("After");
System.out.println("hashmap size: " + h.size());
System.out.println("weakmap size: " + w.size());
System.out.println("Hashmap value: " + h.get("hashkey") + "\t"
+ "weakmap value: " + w.get("weakkey"));
System.out.println(h.entrySet());
System.out.println(w.entrySet());
}
}
Output is:
Before
hashmap size: 1
weakmap size: 1
Hashmap value: 1 weakmap value: 1
null null
After
hashmap size: 1
weakmap size: 0
Hashmap value: 1 weakmap value: null
[hashkey=1]
[]
But when String hkey = new String("hashkey"); String wkey = new String("weakkey");
is replaced with following code, output changes.
String hkey = "hashkey";
String wkey = "weakkey";
Output is:
Before
hashmap size: 1
weakmap size: 1
Hashmap value: 1 weakmap value: 1
null null
After
hashmap size: 1
weakmap size: 1
Hashmap value: 1 weakmap value: 1
[hashkey=1]
[weakkey=1]
Question: Making String literal and String object 'null' impacts in different way in WeakHashMap. What is the reason?
Strings literals are interned, which basically means that there is a cache, mostly referred to as the String pool. So String literals are always strongly referenced - making them not suitable to use as keys in a weak structure e.g. WeakReference
and WeakHashMap
.
The same goes for autoboxed int
s: also Integer
keeps a cache of Integer
objects for int
values in the range [-128, 127]. So you should also not be using int
for keys in a weak structures.
However, you can work around these problems by creating a new object when inserting an entry, e.g. in the following example, the "a" entry will eventually be removed from the map, but the "b" entry will stay in there forever which is infact a memory leak:
WeakHashMap<String, Object> map = new WeakHashMap<>();
map.add(new String("a"), new Object());
map.add("b", new Object());
The same example is valid for integers:
WeakHashMap<Integer, Object> map = new WeakHashMap<>();
map.add(new Integer(56), new Object());
map.add(57, new Object());
Here the entry for 57 will stay in there forever, because of Integer
's caching, but the 56 entry can be removed by the garbage collector.
Also Boolean
has caching, but only for 2 values of course. Where Integer
has 256 potentially dangerous values, String
practically has unlimited occurences that can be dangerous - you only have to use literals (or use String.intern()
) to create them. It might be that there exist other dangerous classes, too.
Making String literal and String object 'null' impacts in different way in WeakHashMap. What is the reason?
First, you can't make an object null
. You can make a variable reference null
or reference an object, but making an object null
is not a concept that exists.
The javadoc of WeakHashMap
states
An entry in a
WeakHashMap
will automatically be removed when its key is no longer in ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector, that is, made finalizable, finalized, and then reclaimed.
At runtime, the JVM creates an String
object for every String
literal it sees while loading classes. These objects cannot be GC'ed until the ClassLoader
that loaded them is GC'ed, regardless of them being referenced in a WeakHashMap
.
This would be similar to doing
String wkey = new String("weak");
String other = wkey;
Since you have a reachable reference to the object somewhere else, it cannot be GC'ed, even if used in a weak collection.
Also note that System.gc()
does not guarantee that Garbage Collection will run. Be mindful of that when using it as to not misinterpret results.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With