This previous blog introduces the differences and usage scenarios of 4 references in Java, as mentioned in the final summary:
" soft and weak references are not very different, and the JVM first sets the referent field values in SoftReference and weakreference to null before adding to the reference queue, whereas virtual references are different if the objects in a heap have only virtual references, The JVM will then add phantomreference to the reference queue, and the JVM will not automatically set the referent field value to null. This summary is written in a rather hasty, and does not give practical examples to substantiate. This article is mainly to reiterate the differences in the following references, and give practical examples, so that readers clearly feel their differences.
soft and weak references are not very different, and the JVM first The referent field is set to NULL, and then a soft or weak reference is added to the associated reference queue. We can assume that the JVM reclaims the memory occupied by the heap object before adding a soft or weak reference to the reference queue .
Instead of a virtual reference, the JVM does not automatically set the Referent field of the virtual reference to null, but instead preserves the memory space of the heap object and joins the phantomreference directly to the associated reference queue, that is, if we do not manually invoke the Phantomreference.clear (), the heap object memory that the virtual reference points to is not freed.
Referent is a private field of the Java.lang.ref.Reference class, although there is no common API to access this field, but we can get the value of this field by reflection, so we can know that the reference is added to the reference queue, referent is not NULL in the end. SoftReference and WeakReference are the same, here we take
Package Ref.referent;import Java.lang.ref.reference;import Java.lang.ref.referencequeue;import Java.lang.ref.weakreference;import java.lang.reflect.field;//will report null pointer: Referent in WeakReference is set to NULL, After adding to Referencequeuepublic class Testweakreference{private static volatile Boolean isrun = true;private static volatile Re ferencequeue<string> referencequeue = new referencequeue<string> ();p ublic static void Main (string[] args) Throws exception{string ABC = new String ("abc"); System.out.println (Abc.getclass () + "@" + abc.hashcode ()); new Thread () {public void run () {while (Isrun) {Object o = Referen Cequeue.poll (); if (o! = null) {Try{field rereferent = Reference.class.getDeclaredField ("referent"); Rereferent.setaccessible (true); Object result = Rereferent.get (o); SYSTEM.OUT.PRINTLN ("GC would collect:" + result.getclass () + "@" + result.hashcode ());} catch (Exception e) {e.printstacktrace ();}}}}}. Start ();//object is weakly accessible weakreference<string> weak = new Weakreference<string> (abc,referencequeue); System.out.println ("weak=" + weak);//clear strong reference, trigger GCABC = null; System.GC (); Thread.Sleep (+); isrun = false;}}
running this code will find that the null pointer exception is reported in the thread we created. When we clear the strong reference and trigger the GC, the JVM detects that the new String ("ABC") object in this heap is only weakreference, then the JVM frees the heap object's memory and automatically The referent field of the weakreference is set to null, so Result.getclass () will report a null pointer exception.
code similar to the above, we will
Package Ref.referent;import Java.lang.ref.phantomreference;import Java.lang.ref.reference;import Java.lang.ref.referencequeue;import java.lang.reflect.field;//when Phantomreference joined the ReferenceQueue, The target object memory space is still present and will not be reclaimed.//the Referent field in the Phantomreference is not automatically set by the JVM to null//when the target object's phantomreference is added to the referencequeue. The target object is a strong public class Testphantomreference{private static volatile Boolean isrun = true;private static volatile Referen cequeue<string> referencequeue = new referencequeue<string> ();p ublic static void Main (string[] args) throws Exception{string ABC = new String ("abc"); System.out.println (Abc.getclass () + "@" + abc.hashcode ()); new Thread () {public void run () {while (Isrun) {Object o = Referen Cequeue.poll (); if (o! = null) {Try{field rereferent = Reference.class.getDeclaredField ("referent"); Rereferent.setaccessible (true); Object result = Rereferent.get (o); SYSTEM.OUT.PRINTLN ("GC would collect:" + result.getclass () + "@" + result.hashcode ());} catch (Exception e) {e.printstacktrace ();}}}}}.start ();//test Case 1: object is virtual phantomreference<string> phantom = new Phantomreference<string> (ABC, Referencequeue); System.out.println ("phantom=" + phantom);//test Case 2: The object is unreachable and is recycled directly and will not be added to the reference queue//new phantomreference<string> ( ABC, Referencequeue);//clear strong reference, trigger GCABC = null; System.GC (); Thread.Sleep (+); isrun = false;}}
running this code will find that the program does not report an exception, the result is:
class [Email Protected][email protected]gc'll collect:class [email protected]
Obviously, when Phantomreference joins the reference queue, the value of the referent field is not NULL, and the memory space occupied by the heap object still exists. That is, for a virtual reference, the JVM first joins it in the reference queue, and when we delete the Phantomreference object from the reference queue (the object in the heap is unreachable), the JVM frees up the memory space occupied by the heap object. Thus, there is a potential risk of memory leaks using virtual references, because the JVM does not automatically help us to release, and we must ensure that the heap objects it points to are unreachable . From this point of view, a virtual reference is a strong reference, and when memory is low, the JVM does not automatically release the memory occupied by the heap object. Subsequent posts I will perform some oom-related experiments to prove that virtual references do cause oom, while soft and weak references do not cause oom.
Summary:
The above test code is just to help us see the different manifestations of the virtual reference and the soft/weak reference. In actual development, we do not get the value of the Referent field by reflection, and it is meaningless and not worth advocating.
The difference between a virtual reference phantomreference in Java and a weak reference weakreference (soft reference softreference)