Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Stack with weak references

In Java there is a data structure called a WeakHashMap that stores weak references as keys. Whenever the weak references are taken out of memory the entry is removed from the map.

If I have a data structure such as a Stack or a Set where I am storing weak references, will their entries be automatically removed when the weak reference is taken out of memory?

Below is an example of a Stack that stores weak references.

Stack<WeakReference<Object>> objStack = new Stack<WeakReference<Object>>();
like image 512
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz Avatar asked Aug 10 '12 21:08

zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz


2 Answers

Yes. What you're describing is a property of weak references in general, not WeakHashMap specifically.

From the API:

Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object...

like image 58
Pops Avatar answered Sep 24 '22 01:09

Pops


Better late than never.

This is not how weak references work. The WeakReference-object will always be there, but its get()-method may return the original object or null (if the original object was GC:ed).

This means your Stack will always contain a WeakReference-object.

Here's a verbose test I did (however it depends on the JVM doing GC in the middle, which may or may not happen "on command" - try to add some more System.gc():s if it doesn't happen):

public static void main(String[] args) {
    // Set up
    Object object = new Object();
    final WeakReference<Object> weakReference = new WeakReference<>(object);
    final Stack<WeakReference<Object>> references = new Stack<>();      
    references.add(weakReference);

    // Before
    System.out.println("Before:");

    references.forEach(r -> {
        System.out.println("Reference: " + r);
        System.out.println("Object: " + r.get());
    });

    // GC
    object = null;

    System.gc();
    System.gc();
    System.gc();

    // After
    System.out.println("After:");
    references.forEach(r -> {
        System.out.println("Reference: " + r);
        System.out.println("Object: " + r.get());
    });
}

The output:

Before:
Reference: java.lang.ref.WeakReference@238e0d81
Object: java.lang.Object@31221be2
After:
Reference: java.lang.ref.WeakReference@238e0d81
Object: null

Your best approach is probably to just ignore entries where get() returns null once you "pop" them.

Side note: My first test was with a String-object, which never got GC:ed. This is because strings in Java are "interned" (see String.intern()) meaning there is a hidden cache of static strings that are reused. A string will never be GC:ed, unless that pool of strings are full (or something along that line...) I think strings are the only Java object with this "special" characteristic but I'd recommend always using custom made objects in a WeakReference to make sure it gets GC:ed correctly.

like image 24
Erk Avatar answered Sep 20 '22 01:09

Erk