8
votes

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>>();
2
Are you sure it won't return a null value instead? - zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
If you're thinking of using weak references for a real application, please don't do it! The people who build the core library regret adding them as they don't offer any benefit. Watch this presentation if you're interested. - Augusto
Thanks for the video link but I think there are some projects that make good use of WeakReferences. For example check out the Robotium project for Android code.google.com/p/robotium - zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
Mmm, I 'm quite sure I got confused with SoftReferences. Thanks for the link to the project, I'll check it out. - Augusto

2 Answers

2
votes

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...

1
votes

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.