preface

There are two ways that Java performs GC to determine whether an object is alive. One of them is reference counting.

Reference count: Each object in the Java heap has a reference count attribute that increases the count by 1 for every new reference and decreases the count by 1 for every freed reference.

Prior to JDK 1.2, an object could no longer be used by a program if it was not referenced by any variables. That is, an object can only be used by a program if it is reachable.

As of JDK 1.2, references to objects are divided into four levels, giving programs more flexibility over the life cycle of objects. The four levels are in descending order: strong reference, soft reference, weak reference, and virtual reference.

The body of the

1. StrongReference (StrongReference)

Strong references are the most commonly used references. If an object has a strong reference, the garbage collector will never reclaim it. As follows:

    Object strongReference = new Object();
Copy the code

When there is insufficient memory space, the Java Virtual Machine would rather throw an OutOfMemoryError, causing the program to terminate abnormally, than resolve the problem by arbitrarily recollecting objects with strong references. If the strong reference object is not used, it needs to be weakened so that GC can reclaim it, as follows:

    strongReference = null;
Copy the code

If you explicitly set a strongReference object to NULL or let it exceed the lifetime of the object, the GC considers that there is no reference to the object and can reclaim it. Exactly when to collect it depends on the GC algorithm.

    public void test(a) {
        Object strongReference = new Object();
        // Omit other operations
    }
Copy the code

There is a strong reference inside a method that is held in the Java stack, while the actual reference (Object) is held in the Java heap. When the method finishes running, it exits the method stack, the reference object has zero references, and the object is reclaimed.

But if the strongReference is a global variable, you need to set it to NULL when the object is not used, because strong references do not get garbage collected.

ArrayList Clear method:

An array of elementData is defined in the ArrayList class. When the clear method is called to empty the array, each array element is assigned null. Unlike elementData=null, the strong reference still exists, avoiding memory reallocation when elements are added in subsequent calls to methods such as add(). It is especially useful to free memory using reference types in memory arrays such as the clear() method so that memory can be freed in a timely manner.

2. SoftReference

If an object has only soft references, then the garbage collector will not reclaim it if there is enough memory. If the memory space runs out, the memory of these objects is reclaimed. As long as the garbage collector does not reclaim it, the object can be used by the program.

Soft references can be used to implement memory-sensitive caching.

    / / strong reference
    String strongReference = new String("abc");
    / / soft references
    String str = new String("abc");
    SoftReference<String> softReference = new SoftReference<String>(str);
Copy the code

Soft references can be used in conjunction with a ReferenceQueue (ReferenceQueue). If the object referenced by the soft reference is garbage collected, the JAVA VIRTUAL Machine will add the soft reference to the reference queue associated with it.

    ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
    String str = new String("abc");
    SoftReference<String> softReference = new SoftReference<>(str, referenceQueue);

    str = null;
    // Notify GC
    System.gc();

    System.out.println(softReference.get()); // abc

    Reference<? extends String> reference = referenceQueue.poll();
    System.out.println(reference); //null
Copy the code

Note: Soft reference objects are only reclaimed when the JVM is running out of memory. We call the system.gc () method only for notification. When the JVM scans for reclaimed objects is determined by the JVM’s state. Even if a soft reference object is detected, it is not always reclaimed, only when there is insufficient memory.

When memory runs out, the JVM first sets the object reference in the soft reference to NULL and then notifies the garbage collector to collect:

    if(JVM out of memory) {// Set the object reference in the soft reference to NULL
        str = null;
        // Notify the garbage collector to collect
        System.gc();
    }
Copy the code

That is, the garbage collection thread reclaims soft reference objects before the virtual machine throws an OutOfMemoryError, and the virtual machine reclaims soft reference objects that have been unused for a long time as much as possible. “Newer” soft objects that have just been built or used are retained by the virtual machine as much as possible **, which is why ReferenceQueue is introduced.

Application scenario:

The browser’s back button. When you press back, is the content of the back page rerequested or removed from the cache? It depends on the implementation strategy.

  1. If the content of a web page is recycled at the end of browsing, press back to view the page previously browsed, need to rebuild;
  2. If the browsing of the web page stored in memory will cause a lot of memory waste, or even cause memory overflow.

In this case, soft references can be used to solve the real problem:

    // Get the browser object for browsing
    Browser browser = new Browser();
    // Load the browsing page from the background program
    BrowserPage page = browser.getPage();
    // Set the finished page as a soft reference
    SoftReference softReference = new SoftReference(page);

    // Roll back or browse the page again
    if(softReference.get() ! =null) {
        // The memory is sufficient and has not been reclaimed by the collector
        page = softReference.get();
    } else {
        // The soft reference object has been reclaimed because of insufficient memory
        page = browser.getPage();
        // Rebuild the soft reference
        softReference = new SoftReference(page);
    }
Copy the code

3. WeakReference

The difference between a weak reference and a soft reference is that objects with only weak references have a shorter life cycle. When the garbage collector thread scans the area of memory it manages, if it finds an object with only weak references, it will reclaim its memory, regardless of whether the current memory space is sufficient. However, because the garbage collector is a low-priority thread, objects with only weak references are not necessarily quickly discovered.

    String str = new String("abc");
    WeakReference<String> weakReference = new WeakReference<>(str);
    str = null;
Copy the code

The JVM first sets the object reference in the soft reference to NULL and then notifies the garbage collector to collect:

    str = null;
    System.gc();
Copy the code

Note: You should remember an object with Weak Reference if it is used occasionally and you want it to be available whenever you use it, but you do not want to affect garbage collection.

The following code will make a weak reference a strong one again:

    String str = new String("abc");
    WeakReference<String> weakReference = new WeakReference<>(str);
    // Turn a weak reference to a strong reference
    String strongReference = weakReference.get();
Copy the code

Similarly, a weak reference can be used in conjunction with a ReferenceQueue (ReferenceQueue). If the object referenced by the weak reference is garbage collected, the Java virtual machine will add the weak reference to the ReferenceQueue associated with it.

Simple test:

GCTarget.java

public class GCTarget {
    // ID of the object
    public String id;

    // Occupies memory space
    byte[] buffer = new byte[1024];

    public GCTarget(String id) {
        this.id = id;
    }

    protected void finalize(a) throws Throwable {
        // Print the ID of the display object when garbage collection is performed
        System.out.println("Finalizing GCTarget, id is : "+ id); }}Copy the code

GCTargetWeakReference.java

public class GCTargetWeakReference extends WeakReference<GCTarget> {
    // The ID of the weak reference
    public String id;

    public GCTargetWeakReference(GCTarget gcTarget,
              ReferenceQueue<? super GCTarget> queue) {
        super(gcTarget, queue);
        this.id = gcTarget.id;
    }

    protected void finalize(a) {
        System.out.println("Finalizing GCTargetWeakReference "+ id); }}Copy the code

WeakReferenceTest.java

public class WeakReferenceTest {
    // Weak reference queue
    private final static ReferenceQueue<GCTarget> REFERENCE_QUEUE = new ReferenceQueue<>();

    public static void main(String[] args) {
        LinkedList<GCTargetWeakReference> gcTargetList = new LinkedList<>();

        // Create objects with weak references and add them to the list in turn
        for (int i = 0; i < 5; i++) {
            GCTarget gcTarget = new GCTarget(String.valueOf(i));
            GCTargetWeakReference weakReference = new GCTargetWeakReference(gcTarget,
                REFERENCE_QUEUE);
            gcTargetList.add(weakReference);

            System.out.println("Just created GCTargetWeakReference obj: " +
                gcTargetList.getLast());
        }

        // Notify the GC for garbage collection
        System.gc();

        try {
            // Rest for a few minutes and wait for the above garbage collection thread to finish running
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Check whether the associated reference queue is empty
        Reference<? extends GCTarget> reference;
        while((reference = REFERENCE_QUEUE.poll()) ! =null) {
            if(reference instanceof GCTargetWeakReference) {
                System.out.println("In queue, id is: "+ ((GCTargetWeakReference) (reference)).id); }}}}Copy the code

Run WeakReferenceTest. Java, and the running result is as follows:

It can be seen that the life cycle of WeakReference object is basically determined by the garbage collector. Once the garbage collection thread finds the WeakReference object, it will reclaim it in the next GC process.

4. PhantomReference

A dummy reference is, as the name suggests, a dummy. Unlike the other references, virtual references do not determine the life cycle of the object. If an object holds only virtual references, it is just as likely to be collected by the garbage collector at any time as if there were no references at all.

Application scenario:

Virtual references are primarily used to track the activity of an object being collected by the garbage collector. One difference between virtual references and soft and weak references is that:

Virtual references must be used in conjunction with the ReferenceQueue. When the garbage collector is ready to reclaim an object, if it finds that it has a virtual reference, it will add the virtual reference to the reference queue associated with it before reclaiming the object’s memory.

    String str = new String("abc");
    ReferenceQueue queue = new ReferenceQueue();
    // Create a virtual reference that must be associated with a reference queue
    PhantomReference pr = new PhantomReference(str, queue);
Copy the code

A program can determine whether a referenced object is about to be garbage collected by determining whether a virtual reference has been added to the reference queue. If a program finds that a virtual reference has been added to the reference queue, it can take the necessary action before the referenced object’s memory is reclaimed.

conclusion

The level and intensity of the four references in Java from high to low are: strong reference -> soft reference -> weak reference -> virtual reference

When the garbage collector collects, some objects are collected and some are not. The garbage collector marks the living objects from the root Object Object, and then reclaims some unreachable objects and some referenced objects.

To illustrate, the table is as follows:

Reference types Time to be garbage collected use Time to live
Strong reference never The general state of the object Termination occurs when the JVM stops running
Soft references When memory is running out Object caching Terminating when out of memory
A weak reference Normal garbage collection Object caching Terminate after garbage collection
Phantom reference Normal garbage collection Trace the garbage collection of objects Terminate after garbage collection

Welcome to pay attention to the technical public number: one technology Stack

This account will continue to share backend technology essentials, including virtual machine fundamentals, multi-threaded programming, high-performance frameworks, asynchronous, cache and messaging middleware, distributed and microservices, architecture learning and advanced learning materials and articles.