0

I have stored an object as a key in WeakHashMap. Now if I change its value and then call the GC and print map, then nothing is there.

public static void main(String[] args) throws InterruptedException{

    WeakHashMap map = new WeakHashMap();
    Integer obj = new Integer(200);
    map.put(obj, "sgdjsgd");
    obj=new Integer(20);
    System.gc();
    Thread.sleep(2000);
    System.out.println(map);
}
  • expected output: {200,"sgdjsgd"}
  • atual output: {}
sonu kumar
  • 143
  • 1
  • 8
  • 1
    What makes you expect that? *the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector* ([`WeakHashMap` documentation](https://docs.oracle.com/javase/10/docs/api/java/util/WeakHashMap.html)) – Ole V.V. Oct 23 '19 at 09:58
  • 1
    As an aside [don’t use raw types](https://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it). And the `Integer` constructor is deprecated, instead use `Integer.valueOf(200)`, etc. – Ole V.V. Oct 23 '19 at 09:59
  • 2
    It is working exactly as designed. You've thrown away your reference to the key; it only keeps a weak reference to the key; so when you do the `get()` the key and therefore the value may have been garbage-collected. – user207421 Oct 23 '19 at 10:13
  • When you expect the output `{200,"sgdjsgd"}`, you are already acknowledging that there is no relationship between the map and the `obj` variable, which contains `20`. So why do you expect the `obj` variable holding a reference to `20` to prevent the collection of the `200` key? – Holger Oct 23 '19 at 15:45

5 Answers5

1

WeakHashMap may behave as though an unknown thread is silently removing entries.

The WeakHashMap.Entry is a WeakReference object whose referent is the key object you passed to map.put(). That's to say if the key becomes weakly reachable, the garbage collector will atomically declare it finalizable.

The Java SE 8 document says that:

An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization.

In this line of your code

    Integer obj = new Integer(200);
    map.put(obj, "sgdjsgd");

the obj is a strong refernce to the integer object created by new Integer(200) and then it is passed to map.put() which creates a WeakReference (assuming it's called w) to hold this integer object.

But after this line:

obj = new Integer(20);

The obj points to another integer object that holds 20 (the w still points to the integer object that holds 200). But changing the object the obj points to will make the referent of w becomes weakly reachable because it can only be reached by traversing a weak reference (namely the w).

When control returns from the method call to System.gc(), the JVM has made its best effort to recycle all discarded objects. So as is said above, the garbage collector will atomically declare weakly-reachable objects finalizable and finally clear them.

So the w is cleared, the entry in the map is discarded by the garbage collector and as a result, your map contains nothing.

imkiva
  • 11
  • 4
  • Lets go step by step: obj->200 first then when we write map.put(obj, "sgdjsgd"); weakRef->obj->200 then we change obj->20 then it should be weakRef->obj->20 ryt? – sonu kumar Oct 23 '19 at 11:25
  • 2
    No, @sonukumar. `obj=new Integer(20);` assigns a new object to `obj` but does not alter anything inside the map. So the map is (probably) still `{200,"sgdjsgd"}` at this point. – Ole V.V. Oct 23 '19 at 11:54
1

user207421 put it very precisely: Your code is working exactly as designed. It’s not clear to me exactly how you have come to expect something else, but I would like to point out:

  • Your code does not alter anything inside the map. Assigning a new value, 20, to obj only changes that variable. The key in the map is still the Integer holding the value 200.
  • The assignment of 20 to obj makes sure that there are no other references to the key 200 in the map, which is why the garbage collector is allowed to remove that key from the map.

If you wanted to alter the key in the map: don’t ever. A hash map, including a WeakHashMap, stores objects by their hash code. Altering a key object most likely changes the hash code. So the map will not be able to find the key again even though it is in there. If you need this functionality, you must first remove the key from the map and then insert the new key:

    String value = map.remove(obj);
    obj = Integer.valueOf(20);
    map.put(obj, value);

With this change to your code I get this output:

{20=sgdjsgd}

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

With this code you are changing the pointer in the memory that is stored in obj:

obj=new Integer(20);

Before this line, obj held a pointer reference to new Integer(200);

Now, instead, obj holds a pointer reference to new Integer(20); which is different from the previous in the memory.

Therefore, because WeakHashMap holds a weak reference, when the garbage collector runs it collect the object referenced by the map, so when you print the map it shows {} because the pointer saved in the map's key is no more found.

user2342558
  • 5,567
  • 5
  • 33
  • 54
  • Lets go step by step: obj->200 first then when we write map.put(obj, "sgdjsgd"); weakRef->obj->200 then we change obj->20 then it should be weakRef->obj->20 ryt? – sonu kumar Oct 23 '19 at 11:22
0

I am not sure what are you trying to do but What I see in your code is that you assign a new object to a reference that previosly was pointing to a key in the WeakHashMap, by doing that, the original key (Integer(200)) has none pointer so It is useless because you never can reach that key so it is logical that gc will dispose it

JArgente
  • 2,239
  • 1
  • 9
  • 11
0
Integer obj = new Integer(200);

This creates a strong reference by default to Integer object obj ----strong reference ---->200

map.put(obj, "sgdjsgd");

obj ----weak reference ----->200
Now Integer object 200 has both strong and weak reference so it is not eligible for GC

obj=new Integer(20);

obj ----strong reference---->20

obj-----X----->200 obj ----weak reference--->200

Here the existing strong reference to 200 has been lost. So Integer object 200 is only left with weak reference and will be eagerly collected by GC.

And because of this the key also gets deleted from weakHashMap

Check out this link for more details http://www.fis.unipr.it/lca/tutorial/java/refobjs/about/weak.html

sonu kumar
  • 143
  • 1
  • 8