Java: Difference Between Strong/Soft/Weak/Phantom Reference

Can someone explain the difference between Strong, Soft, Weak and Phantom references and the usage of it?

Another good article on the topic:

Java Reference Objects or How I Learned to Stop Worrying and Love OutOfMemoryError, with nice diagrams

http://www.kdgregory.com/images/java.refobj/object_life_cycle_with_refobj.gif

Extract:

As you might guess, adding three new optional states to the object life-cycle diagram makes for a mess.

Although the documentation indicates a logical progression from strongly reachable through soft, weak, and phantom, to reclaimed, the actual progression depends on what reference objects your program creates.

If you create a WeakReference but don't create a SoftReference, then an object progresses directly from strongly-reachable to weakly-reachable to finalized to collected. object life-cycle, with reference objects

It's also important to remember that not all objects are attached to reference objects — in fact, very few of them should be.

A reference object is a layer of indirection: you go through the reference object to reach the referred object, and clearly you don't want that layer of indirection throughout your code.

Most programs, in fact, will use reference objects to access a relatively small number of the objects that the program creates.

References and Referents

A reference object provides a layer of indirection between your program code and some other object, called the referent.

Each reference object is constructed around its referent, and provides a get() method to access the referent. Once you create a reference, you cannot change its referent. Once the referent has been collected, the get() method returns null. relationships between application code, soft/weak reference, and referent

alt text


Even more examples: Java Programming: References' Package

alt text http://www.pabrantes.net/blog/space/start/2007-09-16/1/referenceTypes.png

  • Case 1: This is the regular case where Object is said to be strongly reachable.

  • Case 2: There are two paths to Object, so the strongest one is chosen, which is the one with the strong reference hence the object is strongly reachable.

  • Case 3: Once again there are two paths to the Object, the strongest one is the Weak Reference (since the other one is a Phantom Reference), so the object is said to be weakly reachable.

  • Case 4: There is only one path and the weakest link is a weak reference, so the object is weakly reachable.

  • Case 5: Only one path and the weakest link is the phantom reference hence the object is phantomly reachable.

  • Case 6: There are now two paths and the strongest path is the one with a soft reference, so the object is now said to be softly reachable.

What's the difference between SoftReference and WeakReference in Java?

From Understanding Weak References, by Ethan Nicholas:

Weak references

A weak reference, simply put, is a
reference that isn't strong enough to
force an object to remain in memory.
Weak references allow you to leverage
the garbage collector's ability to
determine reachability for you, so you
don't have to do it yourself. You
create a weak reference like this:

WeakReference weakWidget = new WeakReference(widget);

and then
elsewhere in the code you can use
weakWidget.get() to get the actual
Widget object. Of course the weak
reference isn't strong enough to
prevent garbage collection, so you may
find (if there are no strong
references to the widget) that
weakWidget.get() suddenly starts
returning null.

...

Soft references

A soft reference is exactly like a
weak reference, except that it is less
eager to throw away the object to
which it refers. An object which is
only weakly reachable (the strongest
references to it are WeakReferences)
will be discarded at the next garbage
collection cycle, but an object which
is softly reachable will generally
stick around for a while.

SoftReferences aren't required to
behave any differently than
WeakReferences, but in practice softly
reachable objects are generally
retained as long as memory is in
plentiful supply. This makes them an
excellent foundation for a cache, such
as the image cache described above,
since you can let the garbage
collector worry about both how
reachable the objects are (a strongly
reachable object will never be removed
from the cache) and how badly it needs
the memory they are consuming.

And Peter Kessler added in a comment:

The Sun JRE does treat SoftReferences differently from WeakReferences. We attempt to hold on to object referenced by a SoftReference if there isn't pressure on the available memory. One detail: the policy for the "-client" and "-server" JRE's are different: the -client JRE tries to keep your footprint small by preferring to clear SoftReferences rather than expand the heap, whereas the -server JRE tries to keep your performance high by preferring to expand the heap (if possible) rather than clear SoftReferences. One size does not fit all.

When to use Weak and Phantom references in Java

You can use weak references for cache, simply like soft references as you said.

What good are PhantomReferences? I'm only aware of two serious cases for them: first, they allow you to determine exactly when an object was removed from memory. They are in fact the only way to determine that. This isn't generally that useful, but might come in handy in certain very specific circumstances like manipulating large images: if you know for sure that an image should be garbage collected, you can wait until it actually is before attempting to load the next image, and therefore make the dreaded OutOfMemoryError less likely.

Second, PhantomReferences avoid a fundamental problem with finalization: finalize() methods can "resurrect" objects by creating new strong references to them. So what, you say? Well, the problem is that an object which overrides finalize() must now be determined to be garbage in at least two separate garbage collection cycles in order to be collected. When the first cycle determines that it is garbage, it becomes eligible for finalization. Because of the (slim, but unfortunately real) possibility that the object was "resurrected" during finalization, the garbage collector has to run again before the object can actually be removed. And because finalization might not have happened in a timely fashion, an arbitrary number of garbage collection cycles might have happened while the object was waiting for finalization. This can mean serious delays in actually cleaning up garbage objects, and is why you can get OutOfMemoryErrors even when most of the heap is garbage.

for more details see this page :
http://weblogs.java.net/blog/2006/05/04/understanding-weak-references

Which reference Finalizer (FinalReference) or Weak/Phantom/Soft Reference have higher priority for GC

I think, your question is not about the time of enqueuing, actually.

Consider the Notification section of the package documentation

Some time after the garbage collector determines that the reachability of the referent has changed to the value corresponding to the type of the reference, it will add the reference to the associated queue.

(Note the “some time after”)

and likewise, all reference types have a statement of the form:

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 and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references. At the same time it will declare all of the formerly weakly-reachable objects to be finalizable. At the same time or at some later time it will enqueue those newly-cleared weak references that are registered with reference queues.

(taken from the WeakReference; Note the “at the same time or at some later time”)

In practice, the garbage collector hands over the discovered references to another thread which does the enqueuing asynchronously. Since an unspecified delay makes the order in which an application will retrieve the references from a queue undeterministic, it’s pointless to ask about an order here.

However, I suppose, you’re actually interested in the other “certain point in time”, when “the garbage collector determines that the reachability of the referent has changed to the value corresponding to the type of the reference” and will decide to clear the references atomically and make them eligible for enqueuing.

When there is a mixture of multiple differently typed reference objects, including a Finalizer reference, but no strong reference, there are two possible scenarios:

  1. There is at least one soft reference and there is no memory pressure. Then, the garbage collector may decide not clear resp. enqueue any reference.
  2. There is no soft reference or the garbage collector decides that memory pressure justifies clearing soft references. Then all soft and weak references are cleared and all soft, weak, and finalizer references are handed over for enqueuing.

    Only phantom references stay untouched.

Note that once finalization started, there is no Finalizer reference anymore, but during finalization, new soft or weak reference might get created. So the resulting scenarios are the same as with the optimized handling of objects having a trivial finalize() method. There can be a mixture of soft, weak, and phantom references, without a Finalizer reference. When there is no remaining strong reference, we again have the two possible scenarios:

  1. There is at least one soft reference and there is no memory pressure. Then, the garbage collector may decide not clear resp. enqueue any reference.
  2. There is no soft reference or the garbage collector decides that memory pressure justifies clearing soft references. Then all soft, weak, and phantom references are clearedA and all soft, weak, and phantom references are handed over for enqueuing.

A phantom references are cleared in Java 9 or newer. In previous versions they are only enqueued without being cleared.

Rationale for Soft-/Weak-/PhantomReferences clearing references to objects which have reference to tracked object

We first have to note, that this sentence has been copied from the documentation for soft and weak references to the documentation for phantom references for Java 9, to accommodate changes made in that version, but is not a good fit for phantom references, so the rationale behind it is better explained for soft and weak references.

Suppose you have the following situation:

(weak)→ A
(weak)→ B (strong)→ A

technically, both A and B are weakly reachable, but we can change this be invoking the get() method on either weak reference, to retrieve a strong reference to its referent.

When we do this on the first weak reference, to retrieve a strong reference to A, the object B will stay weakly reachable, but when we do this to get a strong reference to B, the object A will also become strongly reachable, due to the strong reference from B to A.

Therefore, we have the rule that if the weak reference to A gets cleared, the weak reference to B must be cleared to, as otherwise, it would be possible to retrieve a strong reference to A via B despite the weak reference to A has been cleared. And to be on the safe side, it must happen atomically, so there’s no possible race condition allowing to retrieve a reference to B between the clearance of the two references.

As said, this is of lesser relevance for phantom references, as those do not allow to retrieve the reference, but there is no reason to treat them differently.

The point here is, that this is not an actual burden, given how garbage collectors actually work. They have to traverse all live references, i.e. strongly reachable objects, and everything not encountered, is garbage per elimination. So when encountering a weak reference during a traversal, it won’t traverse the referent, but remember the reference object. Once it completed the traversal, it will run through all encountered reference objects and see whether the referent has been marked as reachable through a different path. If not, the reference object is cleared and linked for enqueuing.

To address your example:

(strong)→ A
(weak)→ B (strong)→ A

Here, B is weakly reachable regardless of the strong reference to A. When you eliminate the strong reference to A, B still is weakly reachable and may get enqueued. Formally, A is now weakly reachable, but the JVM will never detect that without detecting that B is weakly reachable too. The only way to detect that A is weakly reachable, would be by traversing the reference graph starting at the weakly reachable B. But no implementation does this. The garbage collector will simply clear the weak reference to B and that’s it.



Related Topics



Leave a reply



Submit