What is a reference

In Java, the JVM is responsible for allocating and reclaiming memory, which is a good thing (easy to use; programs no longer have to worry about memory as they do with C) and a bad thing (inflexible). In order to solve the problem of inflexible memory operation, methods such as soft reference can be used.

After JDK 1.2, three kinds of references are introduced: SoftReference, WeakReference, and PhantomReference.

  1. Strong references: The most traditional definition of a “reference” is a reference assignment that is common in program code, i.e. a reference relationship like Object obj=new Object(). As long as strong references exist, the garbage collector will never reclaim the referenced object.
  2. Soft references: Describe objects that are useful, but not necessary. Objects that are only associated with soft references are included in the collection scope for a second collection before an overflow exception occurs. An overflow exception is thrown if there is not enough memory in the collection.
  3. Weak references: Describes objects that are not required, but are weaker than soft references. Objects associated with a weak reference survive only until the next garbage collection occurs. When the garbage collector starts working, objects that are only associated with weak references will be recollected, regardless of whether the current memory is sufficient.
  4. Virtual reference: Is the weakest reference relationship. The existence of a virtual reference does not affect the lifetime of an object, and it is impossible to obtain an object instance through a virtual reference. The only purpose of setting a virtual reference association for an object is to receive a system notification when the object is collected by the collector.

Conclusion:

  • Strong reference: the most common reference Object o = new Object()
  • Soft reference: garbage collector, which reclaims when memory runs out (The cache)
  • Weak references: The garbage collector sees them and collects (Preventing memory leaks) Application instances: WeakHashMap and ThreadLocal
  • Virtual reference: The garbage collector sees it and then collects it, just like it doesn’t exist (Manage out-of-heap memory)DirectByteBuffer -> apply to NIO Netty

Illustrate in one sentence:

JVM is like a country, GC is the chengguan, strong reference is the local people, soft reference is the immigrants, weak reference is the black hukou, which day the chengguan caught and sent away, virtual reference is a sick black hukou, which day you hang up

1. FinalReference

public class Entity {
    // When the object is collected by GC, the finalize method will be called
    // It is not recommended to override this method in production, because it is not known when it will be called, and sometimes it may not be called
    @Override
    protected void finalize(a) throws Throwable {
        System.out.println("finalize");
        super.finalize(); }}Copy the code
/** * Strong references */
public class FinalReference01 {

    public static void main(String[] args) throws IOException {
        Entity entity = new Entity();
        entity = null;
        System.gc();// DisableExplicitGC (DisableExplicitGC)
        
        System.out.println(entity);
        // Block the main thread to give the garbage collector thread time to executeSystem.in.read(); }} Run result: Finalizenull

Copy the code

Strong references are the most commonly used references. Normal references, but when no one points to them, they are recycled. If an object has a strong reference, the garbage collector will never reclaim it. When there is insufficient memory space, the Java Virtual Machine would rather throw an OutOfM moryError and the program terminates unexpectedly than arbitrarily reclaim objects with strong references to solve the memory shortage problem.

2. SoftReference

Prerequisites Set VM parameters: -xmx20m -xx :+PrintGC

/** * When soft references are collected * run parameter -xmx20m -xx :+PrintGC * suitable for caching */
public class SoftReference02 {

    public static void main(String[] args) throws IOException, InterruptedException {
        //10 MB cache data
        byte[] cacheData = new byte[10 * 1024 * 1024];
        // Hold cached data with soft references
        SoftReference<byte[]> softReference = new SoftReference<>(cacheData);
        // softReference Strong reference points to new softReference (); , the new SoftReference() SoftReference points to a cache of 10M from cacheData

        // Remove strong references to cached data
        cacheData = null;
        System.out.println("Before the first GC" + cacheData);
        // Output the reference object of the softReference.
        // This method returns null if the reference object has been cleaned up by the program or garbage collector
        System.out.println("Before the first GC" +softReference.get());


        // Check the collection status of objects after a GC
        System.gc();
        / / wait for GC
        Thread.sleep(500);

        System.out.println("After the first GC" + cacheData);
        System.out.println("After the first GC" + softReference.get());

        // Allocate another array, the heap memory will not be able to hold, the system will perform garbage collection (GC), first collection, if not enough, the soft reference will be collected
        byte[] byteArr = new byte[12 * 1024 * 1024];
        System.out.println("After distribution" + cacheData);
        System.out.println("After distribution"+ softReference.get()); }} Test result: before the first GCnull[B@7adf9f5f [GC (system.gc ()) 12677K->11117K(19968K),0.0014362 secs]
[Full GC (System.gc())  11117K->11074K(19968K), 0.0068026 secs] after the first GCnullAfter the first GC [B@7adf9f5f [GC (Allocation Failure)  11299K->11106K(19968K), 0.0014352 secs]
[GC (Allocation Failure)  11106K->11138K(19968K), 0.0007573 secs]
[Full GC (Allocation Failure)  11138K->11007K(19968K), 0.0117733 secs]
[GC (Allocation Failure)  11007K->11007K(19968K), 0.0034667 secs]
[Full GC (Allocation Failure)  11007K->749K(16384K), 0.0206738 secs] After allocationnullAfter the distributionnull
Copy the code

As you can see from the above example, objects associated with soft references are not collected by GC. If the Heap space is insufficient during Allocation, the JVM performs a GC. This GC does not collect the soft reference associated objects, but if the JVM finds that the collection is insufficient even after one collection (Allocation Failure), the JVM attempts a second GC to reclaim the soft reference associated objects.

Functions such as if memory is sufficient, then GC retains, if memory is insufficient, then GC collects it are well suited for caching reference scenarios. If it’s in the cache, get it from the cache. If it’s not in the database, get it from the database. The reason the cache exists is to speed up computation.

Soft references are used to describe objects that are useful but not necessary. Objects associated with soft references are listed for a second collection before a memory overflow exception occurs. If there is not enough memory in this collection, the memory overflow exception will be thrown.

Soft reference: garbage collector, which reclaims (cache) when memory is low

3. WeakReference

/** * weak references, */
public class WeakReference03 {

    public static void main(String[] args) throws IOException, InterruptedException {
        //10 MB cache data
        byte[] cacheData = new byte[10 * 1024 * 1024];
        // Hold cached data with soft references
         //weakReference strong reference points to new weakReference (); ,new WeakReference() points to the cache of cacheData 10M
        WeakReference<byte[]> weakReference = new WeakReference<>(cacheData);

        System.out.println("Before the first GC" + cacheData);
        System.out.println("Before the first GC" + weakReference.get());

        // Check the collection status of objects after a GC
        System.gc();
        / / wait for GC
        Thread.sleep(500);

        System.out.println("After the first GC" + cacheData);
        System.out.println("After the first GC" + weakReference.get());

        // Remove strong references to cached data
        cacheData = null;
        System.gc();
        / / wait for GC
        Thread.sleep(500);

        System.out.println("After the second GC" + cacheData);
        System.out.println("After the second GC"+ weakReference.get()); }} Execution result: Before the first GC [B@7adf9f5f before the first GC [B@7adf9f5f after the first GC [B@7adf9f5f after the first GC [B@7adf9f5f after the second GCnullAfter the second GCnull    
Copy the code

Weak references are also used to describe non-mandatory objects, which are weaker than soft references. An object associated with a weak reference will be collected if it is associated with only a weak reference (no strong reference is associated with it).

Weak reference: The garbage collector will recycle the application instance when it sees it (to prevent memory leakage) : WeakHashMap, ThreadLocal

4. PhantomReference

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.LinkedList;
import java.util.List;

/** * Virtual reference, */
public class PhantomReference04 {

    private static final List<Object> LIST = new LinkedList<>();
    private static final ReferenceQueue<Entity> QUEUE = new ReferenceQueue<>();

    public static void main(String[] args) {
        // //phantomReference Strong reference points to new phantomReference (); New PhantomReference(); new PhantomReference();
        PhantomReference<Entity> phantomReference = new PhantomReference<>(new Entity(), QUEUE);

        System.out.println(phantomReference.get());

        new Thread(() -> {
            while (true) {
                LIST.add(new byte[1024 * 1024]);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    // End the current thread
                    Thread.currentThread().interrupt();
                }
                System.out.println(phantomReference.get());
            }
        }).start();

        // Garbage collection thread
        /** * For each garbage collection, observe the queue for a virtual reference collection record. * If there is a virtual reference collection record in the queue, obtain the virtual reference object and observe whether it points to out-of-heap memory. * If it points to out-of-heap memory, the JVM is responsible for garbage collection ** similar to: Garbage collector will observe this queue, there is data in the queue, indicating that the object referred to by a virtual reference has been collected. * THE JVM performs special processing on the object in the queue (whether it points to the out-of-heap memory (this region does not belong to GC management), if it points to the corresponding garbage collection) */
        new Thread(() -> {
            while (true) {
                Reference<? extends Entity> poll = QUEUE.poll();
                if(poll ! =null) {
                    System.out.println("-- virtual reference pairs are reclaimed by the JVM --" + poll);
                }
            }
        }).start();
        try {
            Thread.sleep(500);
        } catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code

The existence of a virtual reference does not affect the lifetime of an object, and it is impossible to obtain an instance of an object through a virtual reference. The only purpose of setting a virtual reference association for an object is to receive a system notification when the object is collected by the collector. Both the virtual reference and the weak reference have no effect on the reclaiming of the associated object. If only the virtual reference and the weak reference are associated with the object, then the object will be recollected. The difference is that the get method for a weak reference always returns null for a virtual reference. The ReferenceQueue can be used for a weak reference. The virtual reference must be used in conjunction with the ReferenceQueue. Objects marked as virtual references are queued and then collected when GC occurs.

The JDK uses virtual references to reclaim direct memory. Since the JVM automatically manages heap memory and direct memory is outside the heap, both direct memory allocation and reclamation are handled by the Unsafe class. The object is managed by the garbage collector. Once the object is reclaimed, the corresponding user thread is notified and the direct memory is cleaned up.

Compared to the above mentioned references, it is not particularly useful for you to keep track of the garbage collection activity of the object. Some people describe the false quote as – “death certificate, the general living people are not at all, only when the people die, go to the crematorium to find out who is dead”

The main application of virtual references is to manage direct memory

GC reclaims heap memory

The JVM reclaims out-of-heap memory

conclusion

Reference types Recovery time use Time to live
Strong reference never The general state of the object When the JVM stops running
Soft references Out of memory Object caching Out of memory
A weak reference JVM garbage collection Object caching The gc to run after
Phantom reference The unknown The unknown The unknown

reference

  1. Soft references, weak references, and virtual references – Their characteristics and application scenarios
  2. Java about the difference and usage of strong references, soft references, weak references and virtual references
  3. [Java] Strong reference, weak reference, soft reference, virtual reference