1. Reference in Java
Reference is the bridge between heap and stack in java. If you want to access objects in the heap, you must access them through reference (except for 8 basic data types)
In garbage collection, if an object is still referenced by GcRoots, it will not be recycled (strong reference). This is not absolute. It is mainly determined according to the reference type
There is also an abstract class Reference for in the jvm
package java.lang.ref; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.access.JavaLangRefAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.ref.Cleaner; /** * Abstract base class for reference objects. This class defines the * operations common to all reference objects. Because reference objects are * implemented in close cooperation with the garbage collector, this class may * not be subclassed directly. * * @author Mark Reinhold * @since 1.2 */ public abstract class Reference<T> { ... }
And soft / weak / virtual references have their own implementation classes
1.1 reference classification
Reference types are mainly divided into four categories. The four types of references behave differently in garbage collection
- Strong references are not recycled
- Recycle when soft reference memory is low
- Weak references are found and recycled
- Virtual reference object tracking recycling
From strong to virtual, the recycling level increases
1.1.1 strong reference
Strong references are basically used in the development process
String str = new String("hello world");
The most common way to create objects is strong reference
The jvm will not recycle this reference. The jvm will recycle only when the reference is set to null
Examples show that:
public class Test1 { public static void main(String[] args) { String str = new String("hello world"); // garbage collection System.gc(); // The thread sleeps for 3s and waits for gc to complete try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } // If it can be printed, it means it has not been recycled System.out.print(str); } }
In general, memory leaks are caused by strong references
1.1.2 soft reference
Soft references are used to make unnecessary but useful objects For example, caching
Soft references are reclaimed when memory is low
The specific logic is:
- Insufficient memory space, garbage collection, reclaiming unreachable objects
- After the unreachable object is reclaimed, the memory space is still insufficient, and the soft reference is reclaimed
- If the memory space is still insufficient after the soft reference is recycled, an error OOM is reported. If the memory space is sufficient, no OOM is reported
Soft references have corresponding implementation classes in the jdk
package java.lang.ref; /** * 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. * * <p> Suppose that the garbage collector determines at a certain point in time * that an object is <a href="package-summary.html#reachability">softly * reachable</a>. 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. * * <p> All soft references to softly-reachable objects are guaranteed to have * been cleared before the virtual machine throws an * {@code 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. * * <p> 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. * * @author Mark Reinhold * @since 1.2 */ public class SoftReference<T> extends Reference<T> { ... }
We use an example to prove that soft references will be recycled when memory is insufficient:
import java.lang.ref.SoftReference; public class SoftReferenceTest { public static void main(String[] args) { // Create a soft reference hello_world is associated with a strong reference object String. Of course, this object cannot be reached after it is created and will be recycled, // Can we still get the object from the soft reference at this time? SoftReference hello_world = new SoftReference(new String("hello world")); // Determines that a String can be obtained through a soft reference System.out.println(hello_world.get().toString()); // Next, set the heap memory size to - Xms10M -Xmx10M -XX:+PrintGCDetails // And trigger garbage collection // Exception capture, and finally output the soft reference try { byte[] bytes = new byte[1024 * 1024 * 10]; }catch (Exception e){ e.printStackTrace(); }finally { System.out.println("After garbage collection"); System.out.println(hello_world.get()); } } }
You can see the results
Before and after garbage collection:
It can be proved that the soft reference will be reclaimed when the memory is insufficient
Note: soft reference recycling refers to objects associated with soft references only. If an object has both weak and strong references, it will not be recycled
1.1.3 weak reference
The recycling of weak references is faster than that of soft references. It will be recycled every time gc. Of course, recycling here also refers to objects with only weak references
This means that the life cycle of a weak reference is only the length of one garbage collection
Weak references also have corresponding implementation classes:
package java.lang.ref; /** * 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. * * <p> Suppose that the garbage collector determines at a certain point in time * that an object is <a href="package-summary.html#reachability">weakly * reachable</a>. 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. * * @author Mark Reinhold * @since 1.2 */ public class WeakReference<T> extends Reference<T> { ... }
Examples of recycling proof for weak references:
import java.lang.ref.WeakReference; import java.util.WeakHashMap; public class WeakReferenceTest { public static void main(String[] args) { WeakReference weakReference = new WeakReference<>(new String("hello world")); System.out.println(weakReference.get()); System.gc(); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("After garbage collection"); System.out.println(weakReference.get()); } }
The results show that:
1.1.4 phantom reference
Virtual references have a higher level of recycling than soft / weak references, and can not be used to obtain the corresponding objects according to virtual references
For an object, having a virtual reference is the same as not having a virtual reference, and has no impact on the life cycle of the object
The only function of virtual reference is to track object recycling. When an object is recycled, it can notify the program that the object has been recycled. Therefore, a virtual reference queue must be specified for the creation of virtual reference
Virtual references also have corresponding implementation classes
package java.lang.ref; import jdk.internal.vm.annotation.IntrinsicCandidate; /** * Phantom reference objects, which are enqueued after the collector * determines that their referents may otherwise be reclaimed. Phantom * references are most often used to schedule post-mortem cleanup actions. * * <p> Suppose the garbage collector determines at a certain point in time * that an object is <a href="package-summary.html#reachability"> * phantom reachable</a>. At that time it will atomically clear * all phantom references to that object and all phantom references to * any other phantom-reachable objects from which that object is reachable. * At the same time or at some later time it will enqueue those newly-cleared * phantom references that are registered with reference queues. * * <p> In order to ensure that a reclaimable object remains so, the referent of * a phantom reference may not be retrieved: The {@code get} method of a * phantom reference always returns {@code null}. * The {@link #refersTo(Object) refersTo} method can be used to test * whether some object is the referent of a phantom reference. * * @author Mark Reinhold * @since 1.2 */ public class PhantomReference<T> extends Reference<T> { ... }
The object recycling notification function of virtual reference can be verified by code:
import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; public class PhantomReferenceTest { static ReferenceQueue referenceQueue = null; /** * The daemon thread listens to the queue. When a virtual reference is recycled, it can see which output object is recycled */ public static class CheckGcThread extends Thread { @Override public void run() { if (referenceQueue != null) { Reference remove = null; try { remove = referenceQueue.remove(); } catch (InterruptedException e) { e.printStackTrace(); } if (remove != null) { System.out.println(remove+"The object was recycled"); } } } } public static void main(String[] args) { // The start queue listening thread is set as the daemon thread, and ends when the main thread ends CheckGcThread checkGcThread = new CheckGcThread(); checkGcThread.setDaemon(true); checkGcThread.start(); // The creation of a virtual reference must be passed into a queue referenceQueue = new ReferenceQueue(); PhantomReference hello_world = new PhantomReference(new String("hello" + " world"), referenceQueue); // Cannot get the value of an object through a virtual reference System.out.println(hello_world.get()); // garbage collection System.gc(); } }
You can see the results:
1.2 expansion
Finalizer reference: it is used to call the finalize method of the object. It is also in the form of queue, which is generally not used
Corresponding implementation class:
package java.lang.ref; /** * Final references, used to implement finalization */ class FinalReference<T> extends Reference<T> { ... }