1. JVM memory area

  • Method area (public) : the user stores information about classes that have been loaded by the virtual machine, constants, static constants, code compiled by the immediate compiler, and other data. Exception status OutOfMemoryError. This includes the constant pool: the user holds the various literal and symbolic references generated by the compiler.

  • Heap (public) : Is the largest chunk of memory managed by the JVM. The only purpose is to store instance objects, and almost all object instances are allocated here. The Java heap is the primary area managed by the garbage collector and is often referred to as the “GC heap”. Exception status OutOfMemoryError

  • Virtual stack (Thread private) : Describes the memory model of Java method execution: each method creates a stack frame as it executes, and the user stores information about local variables, operand stacks, dynamic connections, method exits, and so on. The process of each method from invocation to completion corresponds to the process of a stack frame in and out of the virtual machine stack. Two exception states are defined for this region: OutOfMemoryError StackOverflowError

  • Local method stack (thread private) : similar to the role played by the virtual machine stack. The difference is that the virtual machine stack executes Java methods for the virtual machine, while the Native method stack serves the Native methods used by the virtual machine.

  • Program counter (thread private) : A small block of memory, a line number indicator of the bytecode being executed by the current thread. The bytecode interpreter works by changing the value of this counter to select the next bytecode instruction to execute.

2. Garbage collection

Garbage collection is primarily for the heap and method areas. The three areas of the program counter, virtual machine stack, and local method stack are private to the thread and exist only for the lifetime of the thread and disappear when the thread ends, so there is no need for garbage collection of these three areas.

Determines whether an object is recyclable

Reference counting algorithm

Adds a reference counter to an object that increments by 1 when a reference is added to the object and decays by 1 when a reference fails. Objects with a reference count of 0 can be reclaimed.

In the case of circular references to two objects, the reference counter is never zero, making it impossible to reclaim them. Because of circular references, the Java VIRTUAL machine does not use reference counting algorithms.

public class Test {

    public Object instance = null;

    public static void main(String[] args) {
        Test a = new Test();
        Test b = new Test();
        a.instance = b;
        b.instance = a;
        a = null;
        b = null;
        doSomething(); }}Copy the code

In the above code, the object instances referenced by A and B hold references to each other. Therefore, when we remove the references to a and B, the two Test objects cannot be reclaimed because there are references between the two objects.

Accessibility analysis algorithm

GC Roots is used as the starting point for search. Reachable objects are all alive, and unreachable objects can be recovered.

Java virtual machines use this algorithm to determine whether objects can be reclaimed. GC Roots generally contains the following contents:

  • Objects referenced in the local variable table in the virtual machine stack
  • Objects referenced in JNI in the local method stack
  • The object referenced by the class static property in the method area
  • The object referenced by a constant in the method area

3. Reference types in Java

Whether the number of references is determined by reference counting algorithm or whether the object is reachable by reachability analysis algorithm, the determination of whether the object can be reclaimed is related to references.

Java provides four reference types of varying strength.

1. Strong references: Objects associated with strong references will not be reclaimed. Create a strong reference using new a new object.

Object obj = new Object();
Copy the code

2. Soft references: Objects associated with soft references are reclaimed only when memory runs out. Use the SoftReference class to create a SoftReference.

Object obj = new Object(); SoftReference<Object> sf = new SoftReference<Object>(obj); obj = null; // make objects associated with soft references onlyCopy the code

3. Weak references: An object associated with a weak reference must be reclaimed, that is, it will only survive until the next garbage collection occurs. Use the WeakReference class to create weak references.

Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;
Copy the code

4. Virtual reference: Also known as ghost reference or phantom reference, whether an object has a virtual reference does not affect its lifetime, and an object cannot be obtained through virtual reference. The sole purpose of setting a virtual reference to an object is to receive a system notification when the object is reclaimed. Use PhantomReference to create a virtual reference.

Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj, null);
obj = null;
Copy the code

Garbage collection algorithms

1. Mark – clear

The mark-clear algorithm is divided into two stages: “mark” and “clear” : first, mark all objects that need to be recycled, and uniformly recycle all marked objects after the completion of marking.

Mark-clear algorithm is the most basic collection algorithm, and other collection algorithms are based on this idea and improve its shortcomings.

Inadequate:

  • One is efficiency. The efficiency of both marking and cleaning is not high.
  • The other is the space problem. After the mark is cleared, a large number of discontinuous memory fragments will be generated. Too much space fragment may cause that when the program needs to allocate large objects in the future, it cannot find enough contiguous memory and has to trigger another garbage collection action in advance.

2. Mark and tidy

Move all surviving objects towards one end, and then clean up memory directly beyond the end boundary.

Advantages:

  • No memory fragmentation is generated

Inadequate:

  • A large number of objects need to be moved and the processing efficiency is low.

3. Replication algorithm

Divide the available memory into two equally sized pieces by capacity and use only one piece at a time. When this area of memory is used up, the surviving objects are copied to the other area, and the used memory space is cleaned up again.

In this way, the memory is reclaimed for the whole half region every time, and there is no need to consider the complicated situation of memory fragmentation when allocating memory. As long as the heap top pointer is moved, the memory can be allocated in order, which is simple to implement and efficient to run.

The main disadvantage is that only half of the memory is used.

4. Collect by generation

Current commercial VMS use the generational collection algorithm, which divides the memory into several blocks based on the object lifetime. The collection algorithm is used for each block.

The heap is generally divided into Cenozoic and old age.

  • New generation use: replication algorithm
  • Used in the old days: mark-clean or mark-clean algorithms

5. JVM class loading mechanism

The whole life cycle of a class from being loaded into vm memory to being unloaded from memory includes seven stages: loading, verification, preparation, parsing, initialization, use, and unloading.

1. The load

Three big thing

  1. The binary stream of a class is defined by its fully qualified name
  2. Turn the static storage structure represented by the byte stream into the runtime data structure of the method area
  3. Generate a java.lang.Class object in the method area as an access point to the method area data

Custom class loaders: Override the loadClass () method

One difference: The array classes themselves are not created by the class loader, but are created directly by the VIRTUAL machine, but the array elements are still created by the class loader.

2. Verify

To ensure that the Class file meets the requirements of the current virtual machine, the byte stream data needs to be verified, including format verification, metadata verification, bytecode verification, and symbol reference verification

  • Format verification: Verifies whether the byte stream complies with the class file format specification and can be processed by the current VM. For example, whether the byte stream starts with the magic number 0xCAFEBABE, whether the major and minor versions are processed by the current VM, and whether there are unsupported constant types in the constant pool. Only format-validated byte streams are stored in the method area data structure, and the remaining three validations are based on the method area data.

  • Metadata validation: Semantic analysis of data described by bytecode to ensure compliance with Java language specifications, such as whether final modified classes are inherited, whether abstract methods of the parent class are implemented, and whether final methods or final fields of the parent class are overridden.

  • Bytecode verification: The method body of a class is analyzed to ensure that there will be no events that harm virtual machines when the method is running, such as ensuring the matching of the data type of operand stack and the instruction code sequence, ensuring the correctness of jump instructions, and ensuring the effectiveness of type conversion.

  • Symbolic reference validation: To ensure that subsequent parsing actions can be performed properly, symbolic references are verified, such as whether the corresponding class can be found for the fully qualified name described by string, and whether there is a field descriptor that matches the method in the specified class.

In the preparation phase, memory is allocated in the method area and initial values are set for the class variable (static modifier).

private static int var = 100;
Copy the code

After the preparation phase is complete, the var value is 0 instead of 100. During initialization, 100 is assigned to val, but there is a special case:

private static final int var = 100;
Copy the code

The ConstantValue attribute is generated for VAL during compilation, and the virtual machine assigns VAL a value of 100 from the ConstantValue attribute during preparation.

4. The parsing

The parsing phase is the process of replacing symbolic references in the constant pool with direct references. What is the difference between symbolic references and direct references?

Symbolic references use a set of symbols to describe the referenced target, which can be any literal constant, defined in the Class file format.

2. A direct reference can be a pointer directly to the target, a relative offset, or a handle that can be indirectly located to the target.

4. The initialization

The initialization phase is the execution of a class constructor method that combines the assignment of class variables and static statement blocks in the order they appear in the source file. The merge is done by the compiler.

private static int value = 100;
static int a = 100;
static int b = 100;
static int c;
static {
    c = a + b;
    System.out.println("it only run once");
}
Copy the code
  1. Methods are not necessary for a class or interface. If there is no static code block in a class and no assignment of static variables, the compiler will not generate them.

  2. Methods, unlike instance constructors, do not need to explicitly call methods of the parent class. The virtual machine guarantees that the parent class will be executed first.

  3. To prevent multiple executions, the virtual machine ensures that methods are properly locked and executed synchronously in a multithreaded environment. If more than one thread initializes a class at the same time, only one thread can execute the method, while the others block and wait until execution is complete.

  4. Note: Methods that execute interfaces do not need to execute the parent interface first, only if they use variables defined in the parent interface.

6. Several initializer cases

Referring to a static field of a parent class by subclass does not cause the subclass to initialize:

public class SuperClass{
    public static int value=123;
    static{
        System.out.printLn("SuperClass init!");
    }
}

public class SubClass extends SuperClass{
    static{
        System.out.println("SubClass init!"); } } public class Test{ public static void main(String[] args){ System.out.println(SubClass.value); }}Copy the code

It just prints: SuperClass init! For static variables, only the class that defines the field directly is initialized, so referring to a static variable defined in a parent class by a subclass class only triggers parent class initialization, not subclass initialization.

Referencing a class through an array definition does not trigger initialization of the class:

public class Test{ public static void main(String[] args){ SuperClass[] sca=new SuperClass[10]; }}Copy the code

Constants are stored in the caller’s constant pool at compile time and are not, in essence, directly referenced to the class that defines them, so they do not trigger initialization of the class that defines them

public class ConstClass{
    public static final String HELLO_WORLD="hello world";
    static {
        System.out.println("ConstClass init!"); } } public class Test{ public static void main(String[] args){ System.out.print(ConstClass.HELLO_WORLD); }}Copy the code

No ConstClass init!

7,

Eight,

9,

10,

11,