preface

This article, the first in a series, opens with one goal in mind: How does the JVM use memory

For developers engaged in C, C++ programs, in the field of memory management, they are the emperor with the highest power, both have the ownership of each object, and shoulder the maintenance responsibility of each object life from the beginning to the end.

But for Java programmers, without the need to manage every object with the help of the JVM, it seems that all is well with the JVM managing memory, liberating productivity. But because Java programmers give control of memory to the JVM, it can be a very difficult task to troubleshoot and correct memory leaks and spills without understanding how the JVM is using memory.

So the first step in learning more about the JVM is to understand how it uses memory. With that in mind, we enter this article: take a microscope and look at the guts of the JVM runtime data area.

Overview: THE JVM runtime data area

Below is the internal structure of the JVM runtime data area, we found that the JVM when using memory to memory is divided into different modules, if the JVM as a man, so these modules is its insides, since the insides of the body function is different, so of course, the JVM memory modules must be changed, So let’s start by looking at what are the characteristics of these modules

Oracle defines the JVM specification documentation, which specifies how the JVM is implemented. The documentation is linked to: THE JVM specification Documentation

The JVM’s memory areas are defined in the documentation, which can be roughly divided into five large chunks: heap, stack, local method stack, method area, and program counter

It can be divided into two parts according to the dimension of private and shared threads

  • The stack, the local method stack, and the program counter are private to the thread. Each thread has a unique copy and does not affect each other
  • The heap and method areas are common to all threads

So I’m going to talk about what each module is responsible for in order of unimportant to important in terms of daily contact as a priority

Local method stack

Before we talk about the native method stack, we need to talk about the native method. When we call the Java class library, we often find that the method is modified by the native keyword, especially in the call Thread class, and the native method is modified by the native keyword

Why local methods?

The emergence of native methods is mainly due to the following reasons:

  • Since Java came out in the 1990s, before that, applications were written in C and C ++, so after the advent of Java language, it was necessary to replace the original programs with Java versions, which required a mapping relationship between C, C ++ and Java, thus giving birth to native methods

  • For codes close to the operating system, such as thread scheduling, it is more suitable to be implemented by C and C ++ languages from the perspective of efficiency and implementation difficulty. After all, Java is run on JVM, so there is a method to call C functions through Java code, and this method is native method

In fact, the local method can go further, including how to map to C, C ++ code, what steps have gone through in the process, but because of the relevance of this article is not very strong, so I decided to separate these knowledge points to write an article, here will not continue to expand

Local method stack

The JVM specification document does not enforce any language, usage, or data structure for the methods in the local method stack. Different JVMS are free to implement it as needed. Some Java virtual machines even combine the local method stack with the virtual machine stack.

Like the JVM stack, the local method stack is thread-private and a StackOverflowError is thrown when the stack depth overflows.

The role of the Native method stack is very similar to that of the virtual machine stack (see details later in this article), except that the virtual machine stack executes Java methods for the virtual machine, while the Native method stack uses Native methods for the virtual machine

Program counterProgram Counter Register

Having said the local method stack, let’s take a look at the second module: the program counter, which changes the bytecode instructions recorded to control the branch, loop, jump, exception handling, thread recovery, and other basic functions of the program.

Why do we have program counters

Java code compiled bytecode is interpreted by the bytecode interpreter before being compiled by the JIT real-time compiler

The simple way it works is that the interpreter reads the bytecode loaded into memory and reads the bytecode instructions in sequence. After reading an instruction, translate it into fixed operations, and follow these operations to branch, loop, jump, exception handling, thread recovery, etc.

If your program has only one thread, you don’t really need a program counter. But in a multithreaded environment, as a result of the CPU context switch, it is easy to cause the current thread of execution to a half, just switch to another thread, when another thread to run out, then try to perform the following procedure, and the program counter is used to record the program executive position at the time, when the byte code execution engine performing the next line of code, Dynamically modify the program counter inside the value, change the current code execution position

Program counter features

  1. Thread isolation, each thread has its own program counter when working.
  2. When a Java method is executed, the program counter is valued and records the address of the bytecode instruction being executed

Program counter appearance

The following test code is compiled into a bytecode file and parsed using the javap -v command

public class Test {
    
    public static void main(String[] args) {
        // Test method
        say();
    }
    /** * test method */
    private static void say(a) {
        System.out.println("Hello World"); }}Copy the code

As shown in the following figure, enter the javap -v test. class command and press Enter to run it

Show in front of us is to Test the class bytecode file, bytecode interpreter is according to the order of the file read bytecode instructions, I captures the bytecode, of the main method in the specific program counter deposit can be as simple as below in red circle frame number (real storage is bytecode instruction address)

Program counter and native methodsLove/hate

Remember the local method? For native methods, the method body is not composed of Java bytecode, so the above concept of bytecode line number cannot be applied naturally. So how do you get back to the original position when the native method ends?

The JVM specification for native methods

If the method currently being executed by the thread is native, the value of the Java Virtual Machine’s pc register is undefined

When a thread executes a Native method, the value of the program counter is undefined, not necessarily null, but any value can be used. Native methods exit after execution (stack frame POP), and the method exits and returns to the place where it was called to continue executing the program.

That is, I don’t care what you return, I don’t record, I just record the bytecode line number of the Java method before native, and whatever you return, I’m still calling it back from the original offset address, okay

Methods areaMethod Area

With program counters out of the way, let’s look at the third module: the method area

Function of method area

The method area is used to store the compiled class binaries, which contain information about classes loaded by the JVM, constants, static variables, and just-in-time compiled code. The class information can be viewed as a template, from which the JVM creates instances of each class

Constants and static variables, we usually contact more, here will not repeat, let’s look at the remaining two pieces of content: class information and just-in-time compiled code

The contents stored in the method area

Just-in-time compiled code

The JVM has an optimized called JIT, i.e., instantaneous compiling optimization, Java is interpreted languages, speed type certainly is not the C compiler, so obviously a feasible optimization is the part of the hot bytecode directly compiled into executable machine code is real-time compilers compiled code, so just type and compilation of the same speed

The class information

Class information can be roughly broken down into five parts: the type information, the constant pool of the type, the Field, the Method, and the class variable (all static variables except constants).

The type information

For each type of class loaded, the JVM must store the following type information in the method area:

  • The full valid name of the type

Type names appear as full valid names in both Java class files and the JVM. In Java source code, a full valid name consists of the package name to which the class belongs, followed by a “.”, followed by the class name

For example, if the package of class Object is java.lang, its full name is java.lang.Object, but in the class file, all the “.” are replaced by slash /, making it Java /lang/Object. The representation of a full valid name in the method area varies from implementation to implementation.

  • The full valid name of the type’s immediate parent (interface or java.lang.Object, no parent in either case)

  • Modifiers of this type (some subset of public,abstract, final)

  • An ordered list of the direct interfaces of this type (which interfaces are implemented)

Constant pool of type

The JVM maintains a constant pool for each loaded type. A constant pool is an ordered collection of constants used by this type, including the actual constants, fields (member variables), and symbolic references to methods. Constants in the constant pool are accessed through indexes. Because constant pools store symbolic references to all types, fields (member variables), and methods used by a type, they play a central role in dynamic linking in Java programs.

Dynamic linking will be covered in more detail in the next article class Loading, but what does the method area actually hold

What a Constant pool looks like: The Constant pool portion of a javap decomcompiled bytecode file is the Constant pool

Fields (member variables)

The JVM must keep information about all fields of the type and the order in which the fields are declared in the method area.

Domain information includes domain name, domain type, and domain modifiers (public, private, protected, static, final, volatile, transient).

Method (Method)

The JVM must hold the following information about all methods, including the declaration order, as well as domain information:

  • Method names
  • Method return type (or void)
  • Number and type of method parameters (in order)
  • Method of the modifier (public, private, protected, static, final, synchronized, native, a subset of the abstract)
  • Method bytecodes
  • The operand stack
  • Local variable scale and size (abstract and native methods excluded)
  • Exception table (except for abstract and native methods) the start and end location of each exception handler, the offset address of the code handler in the program counter, and the constant pool index of the caught exception class

Class variables

It’s a static variable of a class. It’s only related to the class, so it’s called a class variable. A class variable is shared by all instances of the class, and you can access it even when there’s no instance of the class. These variables are only relevant to the class, so they become a logical part of the class data in the method area. in

Before a JVM can use a class, it must allocate space in the method area for each non-final class variable.

Static final: Constants are handled differently. Each global constant is assigned at compile time.

Characteristics of method area

  • Access to the method area is thread-safe, and since all threads share the method area, data access in the method area must be designed to be thread-safe. For example, if two threads attempt to access the same class in the method area at the same time, and the class has not yet been loaded into the JVM, only one thread is allowed to load it, and the other threads must wait

  • The method area is created at JVM startup, and its actual physical memory space can be as discontinuous as the Java heap area

  • The size of the method area, like the heap space, can be fixed or scalable

  • Since method is used to save class information area, the size determines the methods system can save many classes, if the system defines the class so much, loading a lot of third-party jars, Tomcat deployment project too much, a lot of the generation of dynamic reflection classes can happen OOM, caused method area overflow, will be thrown out of memory error

Evolution of method area

Experienced JDK version upgrade friend may know, overflow error method area in throwing method area, different versions thrown out of the wrong is not the same, such as jdk1.8 before Java. Lang. OutofMemoryError: PermGenspace, After jdk1.8 is Java. Lang. OutOfMemoryError: Metaspace, this is because the method area has a process of evolution

The evolution process

The Java Virtual Machine specification only specifies the concept of a method area and its role in holding class information, constants, static variables, just-in-time compiler compiled code, and so on. It does not specify how to implement it.

Then, the implementation of the method area must be different on different JVMS. Most of the JVMS used are Sun’s HotSpot. The method section is implemented using persistent generation in HotSpot.

Therefore, we come to the conclusion that the persistent generation is the concept of HotSpot, the method area is defined in the Java virtual Machine specification as a specification, and the persistent generation is an implementation, one is the standard and the other is the implementation.

  • Jdk1.6 or earlier: There is permanent generation. Related information is stored in the permanent generation
  • Jdk1.7: permanent generation exists, but it has been phased out, removing the string constant pool, static variables, and storing them in the heap
  • Jdk1.8 and later: No persistent generation, type information, fields, methods, constants are stored in local memory meta-space, but the string constant pool, static variables are still in the heap

In jdk1.7-JDk1.8, the last JVM to replace the permanent generation with a metacolor

Permanent generation and meta-space

The method area is a specification of the JVM, and the permanent generation and meta-space are concrete implementations of it, in JDK7, and in JDK8, meta-spaces.

The permanent generation

The permanent generation is a contiguous memory space, and its garbage collection is bound to the garbage collection of the old generation. Whenever either memory is full, both regions will be garbage collected. For this reason some people put it in the heap and manage it along with the rest of the heap. We can set the maximum size of the permanent generation with -xx :PermSize and -xx: MaxPermSize. Even if it is not set, the default size is 64M for 32-bit JVMS and 82M for 64-bit JVMS.

dimension

First of all, the biggest difference between a meta-space and a permanent generation is that the meta-space is not in the VIRTUAL machine, but in the local memory, which leads to the default size of the meta-space is unlimited but is limited by the local memory size. To set the MetaspaceSize size, run -xx :MetaspaceSize and -xx :MaxMetaspaceSize.

Why this evolution

  1. Class method information size is difficult to determine, so it is difficult to specify the size of the permanent band, too small is prone to permanent generation overflow, too large is prone to old age overflow.

  2. Persistent bands introduce unnecessary complexity to the GC and are less efficient at collecting. In a persistent generation, metadata may be moved with each Full GC, whereas the Hotspot VIRTUAL machine’s garbage collector of each type deals specifically with metadata in the persistent generation, which can be separated to simplify the Full GC.

  3. Persistent generation is specific to the implementation of hotspot VM, while other JVMS do not have such a thing. Oracle may merge Hotspot and Jrockit into one (different JVM implementations), so it is better to use meta space instead

  4. String constant pools are prone to performance problems and memory overruns if they exist in a persistent generation, with frequent Full GC occurrences

Summary of method area

Method of area to come to an end, the emphasis is on storage and evolution, the contents of the area and class loading is very closely linked, after all, is a class of loading, so in the subsequent speaking class loading, will continue to in-depth analysis method of area, at present, we only need to know the method area are used to do, what is remaining content is ok, don’t dig in, Let’s move on to the fourth module: the stack

The stack

We need to dig the stack module, because in normal contact, the stack is next to the last heap, which means that this area has a deep connection with us, so next, let’s talk about the stack

The characteristics of the stack

  • The stack is thread level, which means that each thread allocates a small area of memory from the total stack space to that thread. This small area of memory is called the thread stack

The structure of the stack

The stack is composed of a stack frame, corresponding to a method a stack frame, each thread executes a method to create a stack frame in its stack space, a method corresponds to a stack frame memory area

The thread stack is the same as the stack in the data structure. It is FILO (first in last out)

In fact, this is consistent with the execution order of our program, the program is always executed after the method of freeing memory space, the stack is kept the same, last on the stack, first off the stack, free the memory area of the stack frame

For example, create a new Math class, as shown in the figure below

public class Math {

    public int compute(a) {
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }
    public static void main(String[] args) {
        Math math = new Math();
        math.compute();
        System.out.println("Hello World"); }}Copy the code

The stack for the main thread should look like this

Since the stack is composed of stack frames, let’s dig into the structure of stack frames

The stack frame

The function of stack frames

Stack frames are data structures used to support method calls and method execution by the JVM

A stack frame stores information about a method’s local variogram, operand stack, dynamic linkage, and method return address. The process of each method from invocation to completion corresponds to the process of a stack frame in the virtual machine stack from loading to unloading. The structure is shown in the figure below:

Local variable scale

Local Variable Table is a group of Variable value storage space used to store method parameters and Local variables defined in methods. The minimum unit of capacity is Variable Slot (64-bit long and double data occupy two Variable slots, and other data types occupy only one). When the Java program is compiled into a Class file, the max_locals data item in the Code property of the method determines the maximum number of slots that the method needs to allocate for the local variable table. The structure of the local variable table is shown below:

Let’s take an example of the representation of the local variable table in bytecode:

public class Test {

    public static void main(String[] args) {
        // Test static methods
        say1();
        // Test the instance method
        Test test = new Test();
        test.say2();
    }
    /** * Test instance method */
    private void say2(a) {
        System.out.println("Hello World------2");
    }
    /** * Test static method */
    private static void say1(a) {
        System.out.println("Hello World------1"); }}Copy the code

Since the local variable table is part of the stack frame, we use javap -v test. class to observe the bytecode associated with the method, using say2 as an example:

  public com.project.mall.Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/project/mall/Test;
Copy the code

LocalVariableTable is the LocalVariableTable of say2, which is made up of slots. In case of instance methods, Slot 0 is reserved for this.

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: invokestatic  #2                  // Method say1:()V
         3: new           #3                  // class com/project/mall/Test
         6: dup
         7: invokespecial #4                  // Method "<init>":()V
        10: astore_1
        11: aload_1
        12: invokevirtual #5                  // Method say2:()V
        15: return
      LineNumberTable:
        line 7: 0
        line 9: 3
        line 10: 11
        line 11: 15
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      16     0  args   [Ljava/lang/String;
           11       5     1  test   Lcom/project/mall/Test;
    MethodParameters:
      Name                           Flags
      args
Copy the code

The first slot in the stack frame corresponding to the main method is not this keyword. This keyword cannot be used in static methods

Why can’t we use this keyword in static methods?

Because this is a reference, the object that calls the method is referred to. Static methods may not be called by an object, so this can’t be referenced. Class methods are all objects belonging to the class itself. Sharing this means that non-static instance members cannot be referenced in static methods of the current instance.

Summary of local variable scale

In short, the local variable table is used to store the parameters of a method and the local variables defined within the method

The operand stack

The function of the operand stack is to record the number generated during the execution of the method. Since it is a stack, it is also a FILO structure

Let’s look at the local variator table and operand stack using a bytecode file as an example:

public class Math {
    public int compute(a) {
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }
    public static void main(String[] args) {
        Math math = new Math();
        math.compute();
        System.out.println("Hello World"); }}Copy the code

Run the javap command to generate a readable bytecode file. Run the javap -c math. class > math. TXT command in the corresponding bytecode package path to generate the bytecode file in the math. TXT file in the same directory

Local variable table and operand stack

Let’s focus on the compute method and look at its local table of variables and operand stack:

  public int compute(a);
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: bipush        10
       9: imul
      10: istore_3
      11: iload_3
      12: ireturn
Copy the code

Compute compute compute compute compute compute compute compute compute compute

  • First line of code iconst_1: pushes int constant 1 to the top of the operand stack.
  • Line 2 istore_1: Stores a value of type int at the top of the operand stack into a local variable table with subscript 1, because subscript 0 is given to this
  • Line 3 iconst_2: pushes int constant 2 to the top of the operand stack
  • Line 4 istore_2: Stores the int value at the top of the operand stack into a local variable table with subscript 2
  • Line 5: iloAD_1: Pushes the second local int variable to the top of the stack. That is, loads the subscript 1 int variable in the local variable table to the top of the operand stack
  • Line 6 iload_2: Pushes the third local int variable to the top of the stack, i.e. loads the local variable with subscript 2 int to the top of the operand stack
  • Line 7 iadd: Add the two int values at the top of the stack and push the result to the top of the stack
  • Line 8 bipush: Pushes the single-byte constant value (-128 to 127) to the top of the stack, followed by 10, which means pushing 10 onto the operand stack
  • Imul: Multiply the top two int values and push the result to the top of the stack
  • Line 10 istore_3: Store the top int value into the fourth local variable and assign it to C
  • Line 11 iload_3: Pushes the fourth local int variable to the top of the stack, the top of the operand stack
  • Ireturn: Returns an int from the current method
Local variable table and operand stack summary

After the above bytecode process analysis, we can find that:

  1. Method of internal variables are stored in local variables and special remind: if it is object type, then the local variables heap for object allocation is stored in the memory address, which is a pointer, rather than objects exist in local variables directly, in a similar array structure for storage, search by means of the subscript

  2. Operand stack: A stack of temporary data generated during the execution of a method for calculation purposes, stored in the data structure of the stack.

Dynamic link

Before we talk about dynamic linking, let’s talk a little bit about what is symbolic referencing

Symbolic reference

In the JVM, a class’s method name, class name, modifier, return value, and so on are a series of symbols, and these symbols are constants stored in the constant pool, and these symbols are loaded into memory with the corresponding memory address, and these memory addresses are direct references

Examples of symbolic references

The javap -v test. class command is used to decompile the compiled file

public class Test {

    public static void main(String[] args) {
        Test test = new Test();
        test.say();
    }
    private void say(a) {
        System.out.println("Hello World"); }}Copy the code

Decompiler file after javap instruction

public class classload.Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC.ACC_SUPER
Constant pool# 1:= Methodref          #8.#24         // java/lang/Object."<init>":()V
   #2 = Class              #25            // classload/Test
   #3 = Methodref          #2.#24         // classload/Test."<init>":()V
   #4 = Methodref          #2.#26         // classload/Test.say:()V
   #5 = Fieldref           #27.#28        // java/lang/System.out:Ljava/io/PrintStream;
   #6 = String             #29            // Hello World
   #7 = Methodref          #30.#31        // java/io/PrintStream.println:(Ljava/lang/String;) V
   #8 = Class              #32            // java/lang/Object
   #9 = Utf8               <init>
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               LocalVariableTable
  #14 = Utf8               this
  #15 = Utf8               Lclassload/Test;
  #16 = Utf8               main
  #17 = Utf8               ([Ljava/lang/String;)V
  #18 = Utf8               args
  #19 = Utf8               [Ljava/lang/String;
  #20 = Utf8               test
  #21 = Utf8               say
  #22 = Utf8               SourceFile
  #23 = Utf8               Test.java
  #24 = NameAndType        #9: #10         // "<init>":()V
  #25 = Utf8               classload/Test
  #26 = NameAndType        #21: #10        // say:()V
  #27 = Class              #33            // java/lang/System
  #28 = NameAndType        #34: #35        // out:Ljava/io/PrintStream;
  #29 = Utf8               Hello World
  #30 = Class              #36            // java/io/PrintStream
  #31 = NameAndType        #37: #38        // println:(Ljava/lang/String;) V
  #32 = Utf8               java/lang/Object
  #33 = Utf8               java/lang/System
  #34 = Utf8               out
  #35 = Utf8               Ljava/io/PrintStream;
  #36 = Utf8               java/io/PrintStream
  #37 = Utf8               println
  #38= Utf8 (Ljava/lang/String;) V {public classload.Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lclassload/Test;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #2                  // class classload/Test
         3: dup
         4: invokespecial #3                  // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: invokespecial #4                  // Method say:()V
        12: return
      LineNumberTable:
        line 7: 0
        line 8: 8
        line 9: 12
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  args   [Ljava/lang/String;
            8       5     1  test   Lclassload/Test;
}
SourceFile: "Test.java"
Copy the code

The Constant pool is our Constant pool, and the Constant pool holds all kinds of symbols

Each symbol has a # next to it. This #1 or #2 is an identifier or locator that the JVM uses for instance creation, variable passing, and method invocation

The invocation of symbolic references

Use the new Test method as an example to see how symbolic references are positioned:

In the main() method, we start with a new Test class, and the comment next to it also indicates that the new is class classload/Test. Let’s see what #2 points to

We can see that #2 is a class, and it points to a #25. Let’s trace it back to #25

As you can see, #25 represents a class with utF8 encoding, and the Test class is finally located in new. So the JVM can step by step find out what class was created by using the identifier of the symbol in the constant pool

Symbolic references and dynamic linking

After Java code is compiled, these method names, (), class names, etc., are converted into symbols and stored in the constant pool. Symbolic references are converted into direct references during class loading or the first time they are used. This conversion is called static resolution. The other part, which is converted to a direct reference at each run, is called the dynamic join

Methods the export

As the name implies, a method exit is some information that needs to be returned after a method has been executed

Once a method is executed, there are only two ways to exit the method.

  • The first way: the execution engine exits a method when it encounters a bytecode instruction returned by the method, such as a return instruction. This way is called normal call completion

  • The second way to exit a method when an exception is encountered during its execution is called exception call completion. A method exits with an exception completion exit without providing any return value to its upper callers.

Normally, when a method exits normally, the value of the method’s PC counter can be used as the return address, and it is likely that this counter value will be stored in the stack frame. When a method exits with an exception, the return address is determined by the exception handler table, and this information is generally not stored in the stack frame.

The heap

Here’s what we know so far

  • Where does local method information exist in the —– method area
  • Where does the class information reside in the —– method area
  • Where do method parameters and local variables and data generated during program execution reside in —– stack

We are left with the last and most important piece of content, the heap —–, the area where objects are stored, followed by the heap

The role of the heap

The Java Heap is an area of memory managed by the Garbage collector, so it is also referred to in some sources as the Garbage Collected Heap, which is the actual area of memory used to hold objects

The structure of the heap

From the perspective of reclaimed memory, since modern garbage collectors are mostly designed based on generational collection theory, they are roughly divided into young generation and old generation, of which the young generation is divided into Eden and Survivor0 and Survivor1 zones (Survivor0 and Survivor1 are also called From and To zones)

But it is important to note that since the JDK 11 introduced ZGC began to appear the new garbage collector USES a generational design, but the current mainstream still USES a generational garbage collector design, so it is with points on behalf of the case, so the structure of the heap as shown in the figure below, by default, the old s accounts for two-thirds of the total heap memory, young generation accounted for a third

So let’s start with the younger generation and look at what are the regions responsible for

The young generation

The whole young generation can be subdivided into Eden zone and survivor zone, and survivor zone can be divided into survivor0 and survivor1

The ratio between Eden and Survivor0 and Survivor1 is 8:1:1 (by default). See below for the relationship between these three zones.

Young GC collection process (Minor GC/Young GC)

Objects that are new/called by reflection in a project are usually stored in Eden. Note that this case is not absolute, so let’s take the usual case as an example

  • When an application runs 24 hours a day, new objects are created constantly, and sooner or later Eden will fill up

  • This is a Young /Minor GC. The bytecode execution engine starts a garbage collection thread in the background to perform Minor GC, collecting useless objects of the Young generation

  • Select useful objects in Eden and copy them to survivor0/survivor1. Allocate them randomly for the first time. Assume that all the remaining objects in Eden are garbage objects

  • If the program continues to execute, the Eden object is no longer fit for survivor0, and the Minor GC is fired again. This time, it will not only reclaim Eden but also the garbage object of survivor0, and put Eden and the useful object of Survivor0 into Survivor1. The remaining garbage objects in Eden and Survivor0 are killed directly

  • If the program continues to execute, the Eden object will not fit again, and the Minor GC will be emitted again. This time, it will not only reclaim Eden but also the garbage object of survivor1, and put Eden and the reference object of Survivor1 into Survivor0. The remaining garbage objects in Eden and Survivor1 are killed directly

  • , in turn, reciprocating cycle, until more than a certain number, the object will be on the old s area, old age can not let go will perform Full GC, articles about Full GC after we again fine, here to know the young generation in the Eden area and Survivor0 area and Survivor1 what the relationship is ok

This paper summarizes

Ok, that’s all the content of this article, let’s review the general context of the article

  1. Part 1: I started by explaining why it is important to understand the JVM runtime data area. What modules are the JVM runtime data areas roughly divided into

  2. The second part describes the data stored in each module in the JVM runtime data area, what is the role of each module, and what role does it play in the JVM

omg

Finally, if you feel confused, please leave a comment in the first time, if you think I have something to ask for a thumbs up 👍 for attention ❤️ for share 👥 for me really very useful!! If you want to obtain the ebook “In-depth Understanding of Java Virtual Machine: ADVANCED features and Best Practices of JVM (3rd edition) Zhou Zhiming”, you can pay attention to wechat public account Java Encyclopedia, finally, thank you for your support!!