This article has participated in the good article call order activity, click to see: [back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!]

preface

As an experienced developer, it is inevitable that you will be asked questions about the JVM in your interview. We have talked about object allocation before. If you want to review the previous article, do you really think objects are allocated on the heap? Now let’s talk about recycling. (Please watch your partner.)

Is it due for recycling

First of all, we need to figure out what kind of objects are being collected. You can’t just use objects that are being garbage collected by the JVM all of a sudden. This would crash programmers, so the JVM needs to figure out exactly who is being garbage collected. There are two main ways for the JVM to determine whether an object needs to be collected: reference counting and reachability analysis. Of course, reference counting is not used for garbage collection in the mainstream Java Virtual Machine (JVM) because it has circular references. We can look at an example

public class ReferenceCountingGC {
    public Object instance = null;
    private static final int _1MB = 1024 * 1024;
    private byte[] bigSize = new byte[2 * _1MB];

    public static void main(String[] args) {
        ReferenceCountingGC objA = new ReferenceCountingGC();
        ReferenceCountingGC objB = new ReferenceCountingGC();
        objA.instance = objB;
        objB.instance = objA;

        objA = null;
        objB = null;
        / / gc manuallySystem.gc(); }}Copy the code

Will objA and objB be reclaimed when we finish executing main? The answer is yes. Let’s look at the output of the heap log. Run – >Edit Configuration and set it to:-XX:+PrintGCDetails Next, let’s run the code and see the log print

D:\tools\jdk\jdk18.. 0 _151\bin\java.exe -XX:+PrintGCDetails "-javaagent:D:\IntelliJ IDEA 2020.3.1\lib\idea_rt.jar=63413:D:\IntelliJ IDEA 2020.3.1\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\tianyaa\AppData\Local\Temp\classpath1008509836.jar com.yuan.server.test.ReferenceCountingGC
[GC (System.gc()) [PSYoungGen: 23425K->2302K(74240K)] 23425K->2310K(243712K), 0.0071882 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (System.gc()) [PSYoungGen: 2302K->0K(74240K)] [ParOldGen: 8K->2077K(169472K)] 2310K->2077K(243712K), [Metaspace: 3547K->3547K(1056768K)], 0.0098817 secs] [Times: user=0.19 sys=0.00, real=0.01 secs] 
Heap
 PSYoungGen      total 74240K, used 427K [0x000000076dc00000.0x0000000772e80000.0x00000007c0000000)
  eden space 64000K, 0% used [0x000000076dc00000.0x000000076dc6ac20.0x0000000771a80000)
  from space 10240K, 0% used [0x0000000771a80000.0x0000000771a80000.0x0000000772480000)
  to   space 10240K, 0% used [0x0000000772480000.0x0000000772480000.0x0000000772e80000)
 ParOldGen       total 169472K, used 2077K [0x00000006c9400000.0x00000006d3980000.0x000000076dc00000)
  object space 169472K, 1% used [0x00000006c9400000.0x00000006c96076e8.0x00000006d3980000)
 Metaspace       used 3557K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 383K.capacity 388K.committed 512K.reserved 1048576K

Process finished with exit code 0
Copy the code

As you can see, 23425K->2370K proves that objA and objB do not escape collection because they reference each other, and that the JVM does not count references to determine whether objects are alive.

Accessibility analysis algorithm

In fact, the current mainstream system adopts the accessibility analysis algorithm to determine whether an object is alive. The logic of this algorithm is roughly as follows

graph TD
GC_Roots --> object1 --> object2
object1 --> object3
object4 --> object5
object4 --> object6 

It can be seen that starting from GC Roots, Object1, Object2 and Object3 can be passed successively. However, object4, Object5 and Object6, although related, do not pass through GC Roots, so when GC occurs, they will still be collected. In the Java architecture, there are several types of objects that can be fixed as GC Roots:

  • Objects referenced in the virtual machine stack
  • An object referenced by a class static property in the method area
  • An object referenced by a constant in the method area
  • Objects referenced by JNI in the local method stack
  • All objects held by the synchronization lock

The final death

So after the reachability analysis, the unreachable object will definitely be recycled? The answer is no, really declaring the death of an object should go through at least two marking processes: if the object is found to have no reference chain connected with GC Roots after the reachability analysis, then it will be marked for the first time, then it will be screened for a time, and whether it is necessary to execute finalize() method for this object when the filtering conditions are met. If the object does not override the Finalize () method, or the method has been called by the virtual machine, then the object will not be reclaimed. Let’s take a look at a little experiment from the book Understanding the Java Virtual Machine:

public class FinalizeEscapeGC {
    public static FinalizeEscapeGC SAVE_HOOK = null;
    public void isAlive(a){
        System.out.println("yse,i am still alive");
    }

    @Override
    protected void finalize(a) throws Throwable {
        super.finalize();
        System.out.println("finalize method executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Exception {
        SAVE_HOOK = new FinalizeEscapeGC();
        // The object succeeds in rescuing itself for the first time
        SAVE_HOOK = null;
        System.gc();
        // Pause 0.5 seconds for Finalize method execution
        Thread.sleep(500);
        if(null! = SAVE_HOOK){ SAVE_HOOK.isAlive(); }else {
            System.out.println("no,i am dead");
        }

        // If the object succeeds the second time, it will not succeed
        SAVE_HOOK = null;
        System.gc();
        // Pause 0.5 seconds for Finalize method execution
        Thread.sleep(500);
        if(null! = SAVE_HOOK){ SAVE_HOOK.isAlive(); }else {
            System.out.println("no,i am dead"); }}}Copy the code

After running, look at the output:

finalize method executed!
yse,i am still alive
no,i am dead
Copy the code

As you can see, the Finalize () method of the SAVE_HOOK object was indeed triggered by the garbage collector and successfully escaped before garbage collection.

conclusion

Above we have learned the different results of object recycling in different scenarios through some code, and also know the object in what case will be really recycled, hope to help you.