Friday, July 25, 2014

StrongReference, WeakReference, SoftReference, and PhantomReference in Java

In this post, we'll look into the different type of references in Java such StrongReference, WeakReference, SoftReference, and PhantomReference with detail knowledge of its working, its uses, its applications in real life. 

Java provides reference-object classes, which support a limited degree of interaction with the garbage collector. A program may use a reference object to maintain a reference to some other object in such a way that the latter object may still be reclaimed by the collector. A program may also arrange to be notified some time after the collector has determined that the reach-ability of a given object has changed.

Package java.lang.ref
A reference object encapsulates a reference to some other object so that the reference itself may be examined and manipulated like any other object. Three types of reference objects are provided, each weaker than the last: soft, weak, and phantom. Each type corresponds to a different level of reachability, as defined below. Soft references are for implementing memory-sensitive caches, weak references are for implementing canonicalizing mappings that do not prevent their keys (or values) from being reclaimed, and phantom references are for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.



Object Life Cycle (without Reference Objects)
An object's life can be summed up by the simple picture below: it's created, it's used, it becomes eligible for collection, and eventually it's collected.


Enter Reference Objects

JDK 1.2 introduced the java.lang.ref package, and three new stages in the object life cycle: softly-reachable, weakly-reachable, and phantom-reachable. These states only apply to objects eligible for collection — in other words, those with no strong references




Strong reference : A normal Java object reference
A strong reference is a normal reference that protects the referred object from collection by a garbage collector. The term is used to distinguish the reference from weak references. An object is strongly reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strongly reachable by the thread that created it.

A strong reference is an ordinary Java reference, the kind you use every day. For example, the code:
StringBuffer ref = new StringBuffer("JavaLatte);
creates a new StringBuffer() and stores a strong reference to it in the variable ref.

The important part about strong references is how they interact with the garbage collector. Specifically, if an object is reachable via a chain of strong references, it is not eligible for garbage collection. As you don't want the garbage collector destroying objects you're working on, this is normally exactly what you want.

Problem with Strong reference
Manual memory de-allocation
There are many situation where we can't extend classes, it might be these simply be marked final it could be something more complicated. Suppose you have to use class FacebookUser and for whatever reason, it isn't possible or practical to extend FacebookUser to add new functionality.

What happens when you need to keep track of extra information about the object? In this case, suppose we find ourselves needing to keep track of each FacebookUser's serial number, but the FacebookUser class doesn't actually have a serial number property -- and because FacebookUser isn't extensible, we can't add one. No problem at all, that's what HashMaps are for:
hashMap.put(FacebookUser,userSerialNumber);
This might look okay, but strong reference to FacebookUser certainly cause problems. We have to know (with 100% certainty) when a particular Widget's serial number is no longer needed, so we can remove its entry from the map. Otherwise we're going to have a memory leak or we may face missing serial number if remove FacebookUser that we are still using. We are not supposed to have to worry about this in a more civilized language like Java.

Caching
Another common problem with strong references is caching, particular with very large structures like images. Suppose you have an application which has to work with user-supplied images. Naturally you want to cache these images, because loading them from disk is very expensive and you want to avoid the possibility of having two copies of the image in memory at once.

Because an image cache is supposed to prevent us from reloading images when we don't absolutely need to, you will quickly realize that the cache should always contain a reference to any image which is already in memory. With ordinary strong references, though, that reference itself will force the image to remain in memory, which requires you (just as above) to somehow determine when the image is no longer needed in memory and remove it from the cache, so that it becomes eligible for garbage collection. Once again you are forced to duplicate the behavior of the garbage collector and manually determine whether or not an object should be in memory.

Summary
  • Garbage collector will not reclaim an object that has a strong reference
Example : In this example, we try to add lots of data into Arraylist which would be more then available memory and we see what would happen in case of strong reference. Obviously, out program will crash or we get OutOfMemoryError.  
We also try to print the status of garbage collection with our program with the help of -XX:+PrintGCDetails


Note : This program may not be perfect elaboration of this concept.
Output

Total memory = 58
Free memory = 58
In btw Free memory = 57
[GC [PSYoungGen: 15744K->2616K(18368K)] 15744K->7416K(60352K), 0.0164850 secs] [Times: user=0.04 sys=0.00, real=0.01 secs] 
In btw Free memory = 47
[GC [PSYoungGen: 18360K->2599K(31488K)] 23160K->14671K(73472K), 0.0190850 secs] [Times: user=0.05 sys=0.02, real=0.02 secs] 
[GC [PSYoungGen: 31463K->2593K(31488K)] 43535K->28161K(73472K), 0.0294520 secs] [Times: user=0.07 sys=0.03, real=0.03 secs] 
[GC [PSYoungGen: 31457K->2624K(31488K)] 57025K->41682K(73472K), 0.0280270 secs] [Times: user=0.06 sys=0.01, real=0.02 secs] 
[Full GC [PSYoungGen: 2624K->0K(31488K)] [PSOldGen: 39058K->41669K(68288K)] 41682K->41669K(99776K) [PSPermGen: 2573K->2573K(21248K)], 0.0607430 secs] [Times: user=0.06 sys=0.00, real=0.07 secs] 
[GC [PSYoungGen: 28864K->2624K(31488K)] 70533K->55557K(99776K), 0.0337830 secs] [Times: user=0.10 sys=0.01, real=0.03 secs] 
[Full GC [PSYoungGen: 2624K->0K(31488K)] [PSOldGen: 52933K->55554K(68288K)] 55557K->55554K(99776K) [PSPermGen: 2573K->2573K(21248K)], 0.0793230 secs] [Times: user=0.08 sys=0.00, real=0.08 secs] 
[Full GC [PSYoungGen: 28864K->3118K(31488K)] [PSOldGen: 55554K->68287K(68288K)] 84418K->71406K(99776K) [PSPermGen: 2573K->2573K(21248K)], 0.1138420 secs] [Times: user=0.11 sys=0.00, real=0.12 secs] 
...many similar lines 
[Full GCException in thread "main"  [PSYoungGen: 28864K->28864K(31488K)] [PSOldGen: 68287K->68287K(68288K)] 97151K->97151K(99776K) [PSPermGen: 2565K->2565K(21248K)], 0.1767070 secs] [Times: user=0.16 sys=0.01, real=0.17 secs] 
[Full GC [PSYoungGen: 28864K->28863K(31488K)] [PSOldGen: 68287K->68287K(68288K)] 97151K->97151K(99776K) [PSPermGen: 2565K->2565K(21248K)], 0.1771830 secs] [Times: user=0.17 sys=0.01, real=0.18 secs] 
[Full GC [PSYoungGen: 28864K->28864K(31488K)] [PSOldGen: 68287K->68287K(68288K)] 97151K->97151K(99776K) [PSPermGen: 2566K->2566K(21248K)], 0.1767730 secs] [Times: user=0.17 sys=0.00, real=0.18 secs] 
[Full GC [PSYoungGen: 28864K->28863K(31488K)] [PSOldGen: 68287K->68287K(68288K)] 97151K->97151K(99776K) [PSPermGen: 2566K->2566K(21248K)], 0.1747700 secs] [Times: user=0.16 sys=0.01, real=0.17 secs] 
[Full GC [PSYoungGen: 28863K->28863K(31488K)] [PSOldGen: 68287K->68287K(68288K)] 97151K->97151K(99776K) [PSPermGen: 2566K->2566K(21248K)], 0.1761940 secs] [Times: user=0.16 sys=0.01, real=0.18 secs] 
[Full GC [PSYoungGen: 28863K->28862K(31488K)] [PSOldGen: 68287K->68287K(68288K)] 97151K->97150K(99776K) [PSPermGen: 2566K->2565K(21248K)], 0.2105580 secs] [Times: user=0.20 sys=0.01, real=0.21 secs] 
Heap
 PSYoungGen      total 31488K, used 28864K [0x00000000fdeb0000, 0x0000000100000000, 0x0000000100000000)
  eden space 28864K, 100% used [0x00000000fdeb0000,0x00000000ffae0000,0x00000000ffae0000)
  from space 2624K, 0% used [0x00000000ffae0000,0x00000000ffae0000,0x00000000ffd70000)
  to   space 2624K, 0% used [0x00000000ffd70000,0x00000000ffd70000,0x0000000100000000)
 PSOldGen        total 68288K, used 68287K [0x00000000f9c00000, 0x00000000fdeb0000, 0x00000000fdeb0000)
  object space 68288K, 99% used [0x00000000f9c00000,0x00000000fdeaffd8,0x00000000fdeb0000)
 PSPermGen       total 21248K, used 2573K [0x00000000f4a00000, 0x00000000f5ec0000, 0x00000000f9c00000)
  object space 21248K, 12% used [0x00000000f4a00000,0x00000000f4c837b8,0x00000000f5ec0000)


You can notice from the above output that out program even didn't completed as we got exception.

Referent
Each reference-object type is implemented by a subclass of the abstract base Reference class. An instance of one of these subclasses encapsulates a single reference to a particular object, called the referent.
Every reference object provides methods for getting and clearing the reference. Aside from the clearing operation reference objects are otherwise immutable, so no set operation is provided. A program may further subclass these subclasses, adding whatever fields and methods are required for its purposes, or it may use these subclasses without change.


Soft reference : java.lang.ref.SoftReference
An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference.

Soft reference objects, which are cleared at the discretion of the garbage collector in response to memory demand. Soft references are most often used to implement memory-sensitive caches. 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  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, 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.

How SoftReference works
Suppose that the garbage collector determines at a certain point in time that an object is softly reachable. At that time it may choose to clear atomically all soft references to that object and all soft references to any other softly-reachable objects from which that object is reachable through a chain of strong references. At the same time or at some later time it will enqueue those newly-cleared soft references that are registered with reference queues.

All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError. Otherwise no constraints are placed upon the time at which a soft reference will be cleared or the order in which a set of such references to different objects will be cleared. Virtual machine implementations are, however, encouraged to bias against clearing recently-created or recently-used soft references.

Direct instances of this class may be used to implement simple caches; this class or derived subclasses may also be used in larger data structures to implement more sophisticated caches. As long as the referent of a soft reference is strongly reachable, that is, is actually in use, the soft reference will not be cleared. Thus a sophisticated cache can, for example, prevent its most recently used entries from being discarded by keeping strong referents to those entries, leaving the remaining entries to be discarded at the discretion of the garbage collector.

Summary
  • Garbage collector is allowed to reclaim an object that has a soft reference but no strong references
  • Can be used, for example, to create a cache of objects that clears itself of no-longer-needed objects if necessary to make room in the heap
  • When memory is not enough, GC can release soft reachable objects.
  • Good implement to data cache.

Soft Reference as Circuit Breaker
A better use of soft references is to provide a "circuit breaker" for memory allocation: put a soft reference between your code and the memory it allocates, and you avoid the dreaded OutOfMemoryError


Example :  Here we use the modified version of above example. In this case, we wrap the ArrayList into SoftReference. When It going to be run of memory, it tries to release the soft reference. In this case, throw out Exception instead of JVM exception.
We also try to print the status of garbage collection with our program with the help of -XX:+PrintGCDetail. As in case of  soft reference, JVM won't claim the space in first pass, that we can verified from the output string "Free memory"


Output

Total memory = 58
Free memory = 58
In btw Free memory = 48
[GC [PSYoungGen: 15744K->2600K(18368K)] 15744K->7424K(60352K), 0.0162960 secs] [Times: user=0.03 sys=0.01, real=0.02 secs] 
In btw Free memory = 47
[GC [PSYoungGen: 18344K->2599K(34112K)] 23168K->14671K(76096K), 0.0171280 secs] [Times: user=0.05 sys=0.01, real=0.02 secs] 
[GC [PSYoungGen: 34087K->2609K(34112K)] 46159K->29417K(76096K), 0.0270800 secs] [Times: user=0.06 sys=0.02, real=0.03 secs] 
[Full GC [PSYoungGen: 2609K->0K(34112K)] [PSOldGen: 26808K->29416K(66048K)] 29417K->29416K(100160K) [PSPermGen: 2573K->2573K(21248K)], 0.0436730 secs] [Times: user=0.05 sys=0.00, real=0.04 secs] 
.. many similar lines
[Full GC [PSYoungGen: 56960K->56960K(113792K)] [PSOldGen: 341376K->341376K(341376K)] 398336K->398336K(455168K) [PSPermGen: 2573K->2573K(21248K)], 0.6748630 secs] [Times: user=0.66 sys=0.01, real=0.68 secs] 
[Full GC [PSYoungGen: 56960K->0K(113792K)] [PSOldGen: 341376K->108K(160384K)] 398336K->108K(274176K) [PSPermGen: 2573K->2566K(21248K)], 0.0952940 secs] [Times: user=0.09 sys=0.00, real=0.09 secs] 
java.lang.RuntimeException:  Ran out of memory Heap
 PSYoungGen      total 113792K, used 1340K [0x00000000f5960000, 0x0000000100000000, 0x0000000100000000)
  eden space 56960K, 2% used [0x00000000f5960000,0x00000000f5aaf250,0x00000000f9100000)
  from space 56832K, 0% used [0x00000000f9100000,0x00000000f9100000,0x00000000fc880000)
  to   space 56832K, 0% used [0x00000000fc880000,0x00000000fc880000,0x0000000100000000)
 PSOldGen        total 160384K, used 108K [0x00000000e0c00000, 0x00000000ea8a0000, 0x00000000f5960000)
  object space 160384K, 0% used [0x00000000e0c00000,0x00000000e0c1b090,0x00000000ea8a0000)
 PSPermGen       total 21248K, used 2575K [0x00000000dba00000, 0x00000000dcec0000, 0x00000000e0c00000)
  object space 21248K, 12% used [0x00000000dba00000,0x00000000dbc83e70,0x00000000dcec0000)
at References.SoftReferenceDemo.fillList(SoftReferenceDemo.java:23)
at References.SoftReferenceDemo.main(SoftReferenceDemo.java:11)


At this point, you may wonder why need to throw out Exception instead OutOfMemoryError as program is going to abort in either case why not just let the out-of-memory error do the job?
The answer is that your application may not be the only thing affected. If you're running on an application server, your memory usage could take down other applications. Even in an unshared environment, a circuit-breaker improves the robustness of your application, because it confines the problem and gives you a chance to recover and continue.


Weak reference : java.lang.ref.WeakReference
An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization

Weak reference functionality is to handle a lot of data without worrying about running out of memory. This works well in lazy-initialization situation where you want to read a potentially large amount of data, but that data is not important enough to be available immediately. For instance, say you are reading 10MB image from the disk in order to determine its feature such as it size, read metadata and for other purposes. But, you don't care about the original data stay in memory. In some situation, we do for from performance perspective.
By default, all java references are strong references- the object on the other end of a strong reference is not garbage collected until the object containing the reference is collected.  That is where WeakReference comes in. Instead of keeping your strong reference in your object, you give it to a WeakReference instance instead. It does the dirty work of allowing the reference to be collected.
Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed. Weak references are most often used to implement canonicalizing mappings
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.

In order to understand weak references, you can check WeakHashMap for more detail.

Example :  Here we use the modified version of above example. In this case, we wrap the ArrayList into WeakReference. As in case of  weak reference every-time when GC start weak reachable object are collected, that we can verified from the output string "Free memory"

Code will similar to above program instead of these line :
static WeakReference<ArrayList<String>> ref = new WeakReference<ArrayList<String>>(new ArrayList<String>());

//throw new RuntimeException(" Ran out of memory ");
Output

Total memory = 58
Free memory = 58
In btw Free memory = 48
[GC [PSYoungGen: 15744K->240K(18368K)] 15744K->240K(60352K), 0.0006910 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
In btw Free memory = 55
[GC [PSYoungGen: 15984K->192K(18368K)] 15984K->192K(60352K), 0.0019730 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC [PSYoungGen: 15936K->160K(18368K)] 15936K->160K(60352K), 0.0004610 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC [PSYoungGen: 15904K->192K(34112K)] 15904K->192K(76096K), 0.0014990 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
... same similar lines
[GC [PSYoungGen: 86944K->32K(83328K)] 87092K->180K(125312K), 0.0001590 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Free memory = 89
Heap
 PSYoungGen      total 83328K, used 35130K [0x00000000f5960000, 0x0000000100000000, 0x0000000100000000)
  eden space 83264K, 42% used [0x00000000f5960000,0x00000000f7ba6988,0x00000000faab0000)
  from space 64K, 50% used [0x00000000fffe0000,0x00000000fffe8000,0x00000000ffff0000)
  to   space 64K, 0% used [0x00000000ffff0000,0x00000000ffff0000,0x0000000100000000)
 PSOldGen        total 41984K, used 148K [0x00000000e0c00000, 0x00000000e3500000, 0x00000000f5960000)
  object space 41984K, 0% used [0x00000000e0c00000,0x00000000e0c25060,0x00000000e3500000)
 PSPermGen       total 21248K, used 2581K [0x00000000dba00000, 0x00000000dcec0000, 0x00000000e0c00000)
  object space 21248K, 12% used [0x00000000dba00000,0x00000000dbc85560,0x00000000dcec0000)

You can notice in this output that after PSYoungGen collection, memory increased from 48 to 55 which is not the case with previous references. Even there is not FullGC happened as weak references are claimed in first pass.


Summary  : 
  • Weaker than soft reference
  • Garbage collector must reclaim an object that has a weak reference but no soft or strong references
  • Can be used, for example, to create a data structure that automatically deletes its own elements when all other references to its elements go away
  • Every time when GC stats, weak reachable objects are collected
  • Disposable objects.


Phantom reference : java.lang.ref.PhantomReference
An object is phantom reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.

Phantom references can be used to perform pre-garbage collection actions such as freeing resources. Instead, people usually use the finalize() method for this which is not a good idea. Finalizers have a horrible impact on the performance of the garbage collector and can break data integrity of your application if you're not very careful since the "finalizer" is invoked in a random thread, at a random time.
In the constructor of a phantom reference, you specify a ReferenceQueue where the phantom references are enqueued once the referenced objects becomes "phantom reachable". Phantom reachable means unreachable other than through the phantom reference. The initially confusing thing is that although the phantom reference continues to hold the referenced object in a private field (unlike soft or weak references), its getReference() method always returns null. This is so that you cannot make the object strongly reachable again. 
From time to time, you can poll the ReferenceQueue and check if there are any new PhantomReferences whose referenced objects have become phantom reachable. In order to be able to to anything useful, one can for example derive a class from java.lang.ref.PhantomReference that references resources that should be freed before garbage collection. The referenced object is only garbage collected once the phantom reference becomes unreachable itself.

How is that different from WeakReference
WeakReferences are enqueued as soon as the object to which they point becomes weakly reachable. This is before finalization or garbage collection has actually happened; in theory the object could even be alive again by an unorthodox finalize() method, but the WeakReference would remain dead.
PhantomReferences are enqueued only when the object is physically removed from memory, and the get() method always returns null specifically to prevent you from being able to alive an almost-dead object.

What good are PhantomReferences
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.

PhantomReferences vs finalize
PhantomReferences avoid a fundamental problem with finalization: finalize() methods can alive objects by creating new strong references to them.  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 possibility that the object was alive 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.

With PhantomReference, this situation is impossible - when a PhantomReference is enqueued, there is absolutely no way to get a pointer to the now-dead object. Because PhantomReference cannot be used to alive an object, the object can be instantly cleaned up during the first garbage collection cycle in which it is found to be phantomly reachable. You can then dispose whatever resources you need to at your convenience.


Arguably, the finalize() method should never have been provided in the first place. PhantomReferences are definitely safer and more efficient to use, and eliminating finalize() would have made parts of the VM considerably simpler.

Summary
  • Weakest reference
  • Garbage collector must reclaim an object that has a phantom reference but no weak, soft, or strong references
  • Can be used, for example, to do post-mortem actions after an object is reclaimed (the object itself cannot be accessed)
  • Work with ReferenceQueue class
  • When the garbage collector determines an object is Phantomly reachable, the PhantomReference object is placed on its ReferenceQueue.
  • The PhatomReference object referred to has been finalized and is ready to be collected.
  • Phantom reference are useful for implementing cleanup operations that are necessary before an object get garbage collected. They are sometime more flexible than the finalize() method.

Difference 
  • Strong Reference
    Purpose : An ordinary reference. Keeps objects alive as long as they are referenced
    Use : normal reference
    When Garbage collected : Any object not pointed to can be reclaimed.
    Implementing Class : default
  • Soft Reference
    Purpose : Keeps objects alive provided there’s enough memory
    Use : to keep objects alive even after clients have removed their references (memory-sensitive caches), in case clients start asking for them again by key.
    When Garbage collected : After a first gc pass, the JVM decides it still needs to reclaim more space
    Implementing Class : java.lang.ref.SoftReference
  • Weak Reference
    Purpose : Keeps objects alive only while they’re in use (reachable) by clients.
    Use : Containers that automatically delete objects no longer in use.
    When Garbage collected : After gc determines the object is only weakly reachable
    Implementing Class : java.lang.ref.WeakReference, java.util.WeakHashMap
  • Phantom reference
    Purpose : Lets you clean up after finalization but before the space is reclaimed (replaces or augments the use of finalize())
    Use : Special clean up processing
    When Garbage collected : After finalization.
    Implementing Class : java.lang.ref.PhantomReference




If you know anyone who has started learning java, why not help them out! Just share this post with them. Thanks for studying today!...

No comments:

Post a Comment