Java: Stack with weak references
Asked Answered
B

2

8

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>>();
Burlesque answered 10/8, 2012 at 21:49 Comment(4)
Are you sure it won't return a null value instead?Burlesque
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.Mesnalty
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/robotiumBurlesque
Mmm, I 'm quite sure I got confused with SoftReferences. Thanks for the link to the project, I'll check it out.Mesnalty
C
2

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

Carboni answered 10/8, 2012 at 21:56 Comment(6)
So if you have a LinkedList of WeakReferences and one of the WeakReferences in the middle of the list goes out of memory, your LinkedList will work as expected?Burlesque
I'm not sure how to answer that... it depends on what you consider to be "as expected."Carboni
I think what I didn't understand is when you call .get() on a WeakReference it gets the actual object. The WeakReference is never set to null just the object it points to.Burlesque
Ah, gotcha. Well, now you know!Carboni
@Burlesque Yes, that's right (about get()). If you then want to get rid of the now-"empty" WeakReference, you'll need to do that manually. If you look at the code for WeakHashMap, you'll see that's what they do.Sheeting
Seems like you would want to first declare your objects (the values) as WeakReference before you add them to WeakHashMap, that way after the key is garbage collected then the value reference will also be weakly collected (otherwise manual cleanup would be necessary)? Am I thinking correctly?Flute
C
1

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.

Congressional answered 30/8, 2019 at 17:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.