This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Introduction to Reference Types

A reference in Java is like the name or alias of an object, and an object requests a chunk of memory to hold data, depending on the size of the object. When you access an object, you don’t access its in-memory data directly, but you access it by reference. A reference is also a data type. You can think of it like a pointer in C++ that indicates an object’s location in memory, except you can’t see what that location is.

If we define more than one reference to the same object, those references are not the same, because a reference is also a data type and requires a stack space to hold it. But their values are the same, indicating the location of the same object in memory (heap space). In Java, reference types are divided into two types: value types and reference types, where value types are basic data types, such as int and double, and reference types are all types except the basic data types. After JDK.1.2, Java extended the concept of references into: There are four kinds of Strong Reference, Soft Reference, Weak Reference and Phantom Reference, and the strength of these four kinds of references decreases successively.

Strong reference

Strong references are the most commonly used references. If an object has a strong reference, the garbage collector will never collect it. When running out of memory, the Java virtual machine would rather throw outofMemoryErrors to abort the program than randomly recycle objects with strong references to resolve the memory problem. For example: A A = new A(). Strong references have the following three characteristics:

Strong references allow direct access to the target object.

Strong references point to objects that are not reclaimed by the system at any time.

Strong references can lead to memory leaks.

The source code is as follows:

/** * Final references, used to implement finalization */ class FinalReference<T> extends Reference<T> { public FinalReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); }}Copy the code

Object that defaults to a strong reference type after being created is the type of universal object reference. The source code for FinalReference has only an empty implementation, indicating that strong references are the “default reference type.”

GC collection issues

The object becomes a temporary strong reference because of the Finalizer reference. Even if there are no other strong references, the object cannot be reclaimed immediately. Objects can only be collected after at least two GC, because FinalizerThread can only be collected after FinalizerThread completes finalize method of objects, and finalize method of objects can be collected after FinalizerThread completes Finalize method of objects. When CPU resources are scarce, FinalizerThread may delay executing the Finalize method of objects due to its low priority. As the Finalize method of objects is not executed late, most F objects may enter into the old generation. At this time, GC of the old generation is easy to be triggered, or even Full GC. The GC pause time will be significantly longer, and even OOM will be caused.

Soft references

Soft references are used to describe objects that are “useful but not necessary.” The recycling strategy for soft references varies slightly between JVM implementations. The JVM takes into account not only the current memory condition, but also the recent use and creation time of the referent to which the soft reference refers. Soft references hold two variables:

Timestamp: the timestamp is updated each time the get method is called. The JVM can use this field to select soft references to clear, but it is not required to do so.

Clock: Time lock, updated by garbage collector

Therefore, any GC can use these fields and define a policy for cleaning up soft references, such as, finally, cleaning up recently created or recently used soft references. After JDK 1.2, a SoftReference class was provided to implement soft references. Soft references can be used to implement memory sensitive caching. A soft reference can be used in conjunction with a ReferenceQueue (ReferenceQueue), and if the object referenced by the soft reference is collected by the garbage collector, the Java virtual machine adds the soft reference to the ReferenceQueue associated with it. The source code is as follows:

/** * Soft reference objects are cleared by the garbage collector depending on memory needs. Soft references are often used to implement memory sensitive caches. * * If the garbage collector determines that an object is soft reachable at some point, it can choose to atomically remove * all soft references to that object, as well as all soft references to other soft reachable objects connected from that object through a strong reference chain. * At the same time, or some time after, it enqueues newly cleared soft references registered with Reference Queues. * * All soft references to soft reachable objects are guaranteed to be cleared before the virtual machine throws an OutOfMemoryError. * However, there are no mandatory constraints on when soft references can be removed and in what order. * However, the virtual machine implementation is encouraged to prefer not to clear recently created or recently used soft references. * * A direct instance of this class can be used to implement simple caching. * This class or its derived subclasses can also be used with larger data structures for more complex caches. * As long as the reference object of the soft reference is strongly reachable, that is, in actual use, the soft reference will not be cleared. * Thus, complex caches can be prevented from being purged by holding strong references to recently used cache objects, * while infrequently used remaining cache objects are at the discretion of the garbage collector. */ public class SoftReference&lt; T&gt; extends Reference&lt; T&gt; { static private long clock; private long timestamp; // Returns a reference to the object. If the reference object has been cleared by the program or garbage collector, null is returned. Timestamp public T get() {T o = super.get(); if (o ! = null &amp; &amp; this.timestamp ! = clock) this.timestamp = clock; return o; }}Copy the code

Here’s an example:

/** * The referent is null when the soft reference is pending. * * Startup parameters: -Xmx5m * */ public class SoftReference { private static ReferenceQueue<MyObject> queue = new ReferenceQueue<>(); public static void main(String[] args) throws InterruptedException { Thread.sleep(3000); MyObject object = new MyObject(); SoftReference<MyObject> softRef = new SoftReference(object, queue); new Thread(new CheckRefQueue()).start(); object = null; System.gc(); System.out.println("After GC : Soft Get = " + softRef.get()); System.out.println(" Allocate large memory "); /** * Full GC fires three times in total. System.gc() for the first time; The trigger; The second time is triggered when new Byte [5*1024*740] is allocated, and it is found that there is not enough memory, so softRef is included in the collection return, followed by the third full GC. */ //byte[] b = new byte[5*1024*740]; /** * also triggers full GC 3 times. System.gc() for the first time; The trigger; The second time is triggered when new Byte [5*1024*740] is allocated, and it is found that there is not enough memory, so softRef is included in the collection return, followed by the third full GC. An OutOfMemoryError is thrown when after the third full GC there is still not enough memory to allocate new bytes [5*1024*740]. */ byte[] b = new byte[5*1024*790]; System.out.println("After new byte[] : Soft Get = " + softRef.get()); } public static class CheckRefQueue implements Runnable { Reference<MyObject> obj = null; @Override public void run() { try { obj = (Reference<MyObject>) queue.remove(); } catch (InterruptedException e) { e.printStackTrace(); } if (obj ! = null) { System.out.println("Object for softReference is " + obj.get()); } } } public static class MyObject { @Override protected void finalize() throws Throwable { System.out.println("MyObject's finalize called"); super.finalize(); } @Override public String toString() { return "I am MyObject."; }}}Copy the code

A weak reference

Used to describe non-essential objects, which are weaker than soft references. Objects associated with weak references only survive until the next garbage collection is sent. Collection begins when objects associated only with weak references are reclaimed regardless of whether there is currently enough memory. When the Java garbage collector is ready to recycle the object that WeakReference points to, the WeakReference object itself will be added to the ReferenceQueue object before calling the Finalize () method of the object. They can then be retrieved via the poll() method of the ReferenceQueue. The source code is as follows:

/** * A weak reference object cannot prevent its own reference from being recycled. * Weak references are often used to implement normalized mappings (object instances can be used simultaneously in multiple places in the program). * * If the garbage collector determines at some point in time that the object is weakly reachable. It then atomically removes all weak references * to the object and all other weakly reachable objects that the reference is connected to through strong or soft references. * At the same time, it will indicate that all weakly reachable objects mentioned above can execute the Finalize method. * At the same time, or at some later time, it enqueues those newly cleared weak references registered with Reference Queues. */ public class WeakReference&lt; T&gt; extends Reference&lt; T&gt; Public WeakReference(T referent) {super(referent); Public WeakReference(T referent, ReferenceQueue&lt; ? super T&gt; q) { super(referent, q); }}Copy the code

Phantom reference

Virtual references are the weakest of all reference types. Whether or not an object is associated with a virtual reference does not affect the life cycle of the object at all, nor can a virtual reference be used to obtain an instance of an object. The only purpose of setting a virtual reference to an object is to receive a system notification when the object is collected by the garbage collector, which is implemented using the ReferenceQueue. When the referent is reclaimed by gc, the JVM automatically adds the virtual reference object itself to the ReferenceQueue, indicating that the referent referred to by the reference is reclaimed. And then you can do extra cleaning by going to the queue and getting a reference. Virtual reference can be used instead of object Finalize method to implement resource release, which is more flexible and secure.

PhantomReference is added to the ReferenceQueue object only when the Java garbage collector actually collects the object to which it points, so that the object’s destruction can be tracked. Here the Referent object’s Finalize () method has already been called. So the specific usage is different from the previous two, it must pass in a ReferenceQueue object. When the object referenced by a virtual reference is ready for garbage collection, the virtual reference is added to the queue. The source code is as follows:

/** * Virtual reference objects are queued with Reference Queues after being checked by the garbage collector, otherwise they will be recycled. * Virtual references are most commonly used to allow for scheduling additional cleanup work more flexibly than Java Finalization mechanisms. * * If the garbage collector determines that a virtual reference object is virtual reachable at some point in time, it joins the reference Queues at that time or later. * * To ensure that the recoverable object remains unchanged, references to virtual references cannot be used: the get method of a virtual reference object always returns NULL. Unlike soft and weak references, virtual references are not automatically cleared by the garbage collector after they have been queued up with Reference Queues. * Objects reachable only by virtual references remain unchanged until all such references have been removed or become unreachable themselves. */ public class PhantomReference&lt; T&gt; extends Reference&lt; T&gt; {// Since objects cannot be accessed through virtual references, this method always returns NULL. public T get() { return null; } // It makes no sense to create a virtual reference with the empty ReferenceQueue queue: its get method always returns NULL, and since it is not enqueued, it will not be enqueued with any preprocessing before cleanup. public PhantomReference(T referent, ReferenceQueue&lt; ? super T&gt; q) { super(referent, q); }}Copy the code

Here’s an example:

public class PhantomReferenceTest { private static ReferenceQueue<MyObject> queue = new ReferenceQueue<>(); public static void main(String[] args) throws InterruptedException { MyObject object = new MyObject(); Reference<MyObject> phanRef = new PhantomReference<>(object, queue); System.out.println(" Create virtual reference: "+ phanRef); new Thread(new CheckRefQueue()).start(); object = null; int i = 1; While (true) {system.out.println (" "+ i++ ++ "); System.gc(); TimeUnit.SECONDS.sleep(1); } /** * After a GC, the system finds the garbage object and calls Finalize () to reclaim memory, but it is not immediately added to the PhantomReference Queue. Because MyObject overrides finalize() and is a non-empty implementation, MyObject is also a Final Reference. So the first GC does the Final Reference thing. * PhantomReference is added to the PhantomReference Queue when the object (MyObject) is actually collected by the garbage collector on the second GC. * Also, there are pauses between each GC, giving the JVM enough time to process; If there is no timeunit.seconds.sleep (1); It may take the fifth or sixth gc to succeed. */ } public static class MyObject { @Override protected void finalize() throws Throwable { System.out.println("MyObject's finalize called"); super.finalize(); } @Override public String toString() { return "I am MyObject"; } } public static class CheckRefQueue implements Runnable { Reference<MyObject> obj = null; @Override public void run() { try { obj = (Reference<MyObject>)queue.remove(); System.out.println(" Delete virtual reference: "+ obj +", virtual reference object: "+ obj.get()); System.exit(0); } catch (InterruptedException e) { e.printStackTrace(); }}}}Copy the code

conclusion

The four Java references are in descending order:

Strong > Soft > Weak > Virtual.

Draw that

1. This event is supported by the Nuggets official details can be found at juejin.cn/post/701221…

2. You can participate through comments and articles related content, and article content related oh!

3. This month’s articles will participate in the lucky draw, welcome more interaction!

4. In addition to the official lottery of nuggets, I will also give peripheral gifts (one mug and several nuggets badges, mugs will be given to fans, badges will be randomly selected, the number of badges will increase according to the number of comments).