2

Here is the code snippet to put some values in WeakHashMap and then removed those from the map. How does it treat the allocated memory?

import java.util.*;
public class WeakHashMap_Main {
    private static Map map;

    public static void main(String args[]) {
        map = new WeakHashMap();
        map.put(new String("ABC"), "XYZ");
        map.put(new String("DEF"), "PQR");

        map.remove("ABC");
        map.remove("DEF");
    }
}
Amol Dixit
  • 611
  • 7
  • 13
  • 7
    Freeing up memory is done by the garbage collector, whenever necessary. There is no guarantee that memory is freed at any particular time; it's up to the garbage collector implementation. Normally, you don't need such strong guarantees. Let the GC do its work and don't worry about it. – Jesper Dec 01 '16 at 11:38
  • Ya that's understood as gc function is well known by now. I was wondering about speciality of week hash map. – Amol Dixit Jan 13 '17 at 18:23

4 Answers4

1

The memory used by a WeakHashMap may be freed in scenarios like the one below:

public static void main(String args[]) {
    Map<String, String> map = new WeakHashMap<>();
    String abc = "ABC";
    String def = "DEF";
    map.put(abc, "XYZ");
    map.put(def, "PQR");
    System.out.println(map.size());  // Guaranteed to be 2.

    // Note: DO NOT remove the map entries!
    // map.remove("ABC");
    // map.remove("DEF");

    // Allow the objects to be reclaimed
    abc = null;
    def = null;

    // Do loads of memory-hungry operations here...
    ...

    System.out.println(map.size());  // MAY POSSIBLY be 0 or 1. Or still 2.
}

It all depends on what the garbage collector decides to do (if anything at all).

The whole point here is that we haven't touched the map after adding the two entries.

Klitos Kyriacou
  • 10,634
  • 2
  • 38
  • 70
  • Is there any reason for not removing the map entries? I understand that making the keys as null would work but I thought removing the kay-value from the WaelHashMap has same effect. Right? – Amol Dixit Dec 02 '16 at 06:25
  • 1
    You can remove the map entries if you want, but then if you're going to do that, you might as well just use an ordinary HashMap. My code example shows the difference between WeakHashMap and HashMap. – Klitos Kyriacou Dec 02 '16 at 09:29
1

Java docs(jdk1.8.0_71) says that,

an entry in a WeakHashMap will automatically be removed if it's 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.

This clearly states that when the key has been discarded, its Entry<K, V> will also be removed from the Map.

Now, lets take a look under the hood and check what happens when the key is removed. The code snippet of remove(Object o) method is as shown below:

public V remove(Object key) {
        Object k = maskNull(key);
        int h = hash(k);
        Entry<K,V>[] tab = getTable();
        int i = indexFor(h, tab.length);
        Entry<K,V> prev = tab[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            if (h == e.hash && eq(k, e.get())) {
                modCount++;
                size--;
                if (prev == e)
                    tab[i] = next;
                else
                    prev.next = next;
                return e.value;
            }
            prev = e;
            e = next;
        }

        return null;
    }

As it can be observed, the method first fetches the array of Entry<K, V> by calling getTable() method. On every call to getTable(), another method expungeStaleEntries() is called. This particular method will play around with a ReferenceQueue<Object> that holds cleared WeakEntries and it removes the stale entries from the Entry<K, V>[] table. The code snippet of this method can be seen below:

/**
     * Expunges stale entries from the table.
     */
    private void expungeStaleEntries() {
        for (Object x; (x = queue.poll()) != null; ) {
            synchronized (queue) {
                @SuppressWarnings("unchecked")
                    Entry<K,V> e = (Entry<K,V>) x;
                int i = indexFor(e.hash, table.length);

                Entry<K,V> prev = table[i];
                Entry<K,V> p = prev;
                while (p != null) {
                    Entry<K,V> next = p.next;
                    if (p == e) {
                        if (prev == e)
                            table[i] = next;
                        else
                            prev.next = next;
                        // Must not null out e.next;
                        // stale entries may be in use by a HashIterator
                        e.value = null; // Help GC
                        size--;
                        break;
                    }
                    prev = p;
                    p = next;
                }
            }
        }
    }

As it can be seen through the code snippet that, each Entry being added to a WeakHashMap, stores that entry in this queue(The calling constructor during a put(K, V) operation is as shown below:

Entry<K,V> e = tab[i];
tab[i] = new Entry<>(k, value, queue, h, e);

) and that same entry is retrieved and removed from the queue during expunge operation. The value of this removed Entry<K, V> is set to null e.value = null, which will be GC'd later. And yes, it doesn't have any control on GC. This is how WeakHashMap facilitates discarding of mapped values with keys.

Shyam Baitmangalkar
  • 1,075
  • 12
  • 18
  • thanks for detailed explanation .. Who calls the expungeStaleEntries()? Is it like any operation on the WeakHashMap will call this function? – Amol Dixit Dec 02 '16 at 06:20
  • 1
    I'm glad that it helped you in your learning. `expungeStaleEntries()` is a private method within `WeakHashMap`. It is called by `private Entry[] getTable()` method like I mentioned in my explanation earlier. Whenever `remove(Object o)` method is called on the map, the `remove()` method in turn calls this `getTable()` to get the valid array `Entries`. – Shyam Baitmangalkar Dec 02 '16 at 06:49
0

Memory is allocated to an object when it is created. Any number of other objects may have a reference to that object, and therefore to its allocated memory.

The garbage collector is an element of the JVM which determines which objects are still referenced (and also which ones are weak-referenced). It puts all the memory which is no longer referenced back in the heap, and it is ready to use again. Under whatever conditions, if memory is low enough etc., it will also put memory referenced only by weak references back in the heap, and do its magic with the weak references so the program can tell they're no longer valid.

So if you put references to objects in a WeakHashMap, and then take them out, and those were the only references to those objects, then the objects are no longer referenced and are available for garbage collection.

arcy
  • 12,845
  • 12
  • 58
  • 103
0

The class WeakHasMap works with WeakReferences of the keys. Normal HashMap works with StrongReferences of the key.

Garbage collection is self regulated by the JVM. We can only try to influence the JVM to execute Garbage collection by invoking System.gc(). HashMap prevents the keys from being garbage collected. WeakHashMap does not prevent the keys from being garbage collected. If there is no StrongReference left for a key which is stored in a normal HashMap, it will remain stored in HashMap until it is explicitly removed, after which the key object will be eligible for Garbage collection. But in case a key without any StrongReference is stored in a WeakHashMap , it will be eligible for Garbage Collection. As soon as the cycle for garbage collection is executed the key will be garbage collected and after that contains method on that key object will return false.

nits.kk
  • 5,204
  • 4
  • 33
  • 55