Usage of WeakHashMap? [duplicate]
Asked Answered
T

5

6

WeakHashMap is an implementation of Map interface where the memory of the value object can be reclaimed by Grabage Collector if the corresponding key is no longer referred by any section of program. So if key is no longer used in program. its Entry object will be garbage collected irrespective of its usage. Its clear till here

This is different from HashMap where the value object remain in HashMap even if key is no longer referred. We need to explicitly call remove() method on HashMap object to remove the value. calling remove will just remove the entry from map. Its readyness for GC will depend whether it is still used somewhere in program or not.

Please find this coding example explaining above

Usage of WeakHashMap over HashMap as per mine understanding

My understanding is we should go for WeakHashMap only when we want to ensure that value object is reclaimed by Grabage Collector when key is no longer referred by any section of program. This makes program memory efficient Is my understanding correct here?

Usage of WeakHashMap as per JavaDocs , i could spot this statement

This class is intended primarily for use with key objects whose equals methods test for object identity using the == operator.

I did not get what above statement meant and how it contrast with mine understanding of WeakHashMap usage. Actually i did not get how this statement is related to usage of WeakHashMap?

UPDATE:- on further carefully reading below statement the javadocs

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. When a key has been discarded its entry is effectively removed from the map, so this class behaves somewhat differently from other Map implementations.

i am revising my understanding for the benefit of me and others

Usage of WeakHashMap over HashMap as per mine revised understanding

We should go for WeakHashMap only when we want to ensure that key-value pair is removed from map on GC run when key is no longer in ordinary use other than map itself.

Examples are :-

    WeakHashMap<Integer, String> numbers = new WeakHashMap<Integer, String>();
    numbers.put(new Integer(1), "one");// key only used within map not anywhere else
    numbers.put(new Integer(2), "two");
    System.out.println(numbers.get(new Integer(1))); // prints "one"
    System.gc();
    // let's say a garbage collection happens here
    System.out.println(numbers.get(new Integer(1))); // prints "null"
    System.out.println(numbers.get(new Integer(2))); // prints "null"


    Object key = new Object();
    m1.put(key, c1);
    System.out.println(m1.size());
    key = null or new Object() ; // privious key only used within map not anywhere else
    System.gc();
    Thread.sleep(100);
    System.out.println(m1.size());
Terceira answered 23/12, 2013 at 11:50 Comment(0)
A
2

This is due to the fact that objects will be garbage collected (GCed) when they are no longer have a strong reference from any other part of the program.

Given a WeakHashMap<MyObject, String> then if we do the following:

MyObject mo = new MyObject();
map.put(mo, "Test");
mo = null;

Then the entry mo -> Test will be eligible for GC. This means that if you have a custom .equals implementation that uses some property of MyObject to test for equality then you cannot later do this:

MyObject mo2 = new MyObject();
map.get(mo2);

Because even though your overridden .equals method may say that mo2.equals(mo) == true it is not the case that mo2 == mo and therefore the entry may have already been GCed.

The point is that if you keep a reference to mo and use that to retrieve the value from the Map then it is the case that that reference must == mo and therefore two things are true:

  1. the entry mo -> Test cannot be gced
  2. you can use an == based .equals method to retrieve the entry from the map

Basically; as the GC will use strong references to test whether an object can be GCed it is best to ensure that your .equals method does the same to avoid confusion.

Arbitrage answered 23/12, 2013 at 12:1 Comment(0)
H
1

The documentation means that this code is not very useful:

WeakHashMap<Integer, String> numbers = new WeakHashMap<Integer, String>();
numbers.put(new Integer(1), "one");
numbers.put(new Integer(2), "two");
System.out.println(numbers.get(new Integer(1))); // prints "one"
// let's say a garbage collection happens here
System.out.println(numbers.get(new Integer(1))); // prints "null"
System.out.println(numbers.get(new Integer(2))); // prints "null"

This would happen for any class where different instances can be equal. The javadoc is just warning you, in case you hadn't noticed already, that this is not helpful.

Hamulus answered 23/12, 2013 at 11:59 Comment(0)
S
1

Run this test

    Object key = new Object();
    WeakHashMap m = new WeakHashMap();
    m.put(key, 1);
    System.out.println(m.size());
    key = null;
    System.gc();
    Thread.sleep(100);
    System.out.println(m.size());

though System.gc does not guarantee running GC but on my Oracle's JVM 7 it always runs and this test prints

1
0

which means that GC removed the entry from map because the key is not referenced from anywhere but map itself

Sheaff answered 23/12, 2013 at 12:4 Comment(0)
R
0

I think that this means that the object test for equality be using the objects location in memory and not just because two different instances happen to 'equal' in their values.

If this is not the case the it is difficult to tell if the key is referenced any more and a different, but 'equal'in values, instance might be referenced and used to look up the value.

It might be clearer if it said that the keys have to have reference equality so that you know when the keys are no longer referenced by anything other that the WeakHashMap instance

Radiosurgery answered 23/12, 2013 at 11:54 Comment(0)
P
0

Building on Evgeniy Dorofeev answer, here is an example with a few gotchas:

import java.util.Map;
import java.util.WeakHashMap;

public class WeakHashMapTest {

    public static void main(String[] args) throws InterruptedException {
        String key = new String();
        Map<String, String> m = new WeakHashMap();

        m.put(key, "value");
        System.out.println(m.size());

        m.put("key", "value");
        System.out.println(m.size());

        m.put(new String(), "value");
        System.out.println(m.size());

        m.put(new String("k"), "value");
        System.out.println(m.size());

        key = null;
        System.gc();
        Thread.sleep(100);

        System.out.println(m.size());
    }
}

Output

1
2
2
3
1
Pleader answered 19/7, 2017 at 8:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.