JDK architecture

The Java Development Kit (JDK) is the most commonly used Java Development Kit. The JDK includes the Java Runtime Environment (JRE). As you can see from the figure above, the JRE contains our JVM and a variety of core libraries that we commonly use. The JDK extends utility commands on it, such as Java Javac javap these common commands.

Second, the Java language cross-platform features

Java’s cross-platform features are largely a credit to the JVM, and Java officially provides JDK downloads for different platforms and versions

3. JVM memory model

The Java virtual machine is composed of three parts: the classloading subsystem, the runtime memory region (Java memory model), and the bytecode execution engine. The class loading subsystem is the process of class loading as you can see in my last post:An in-depth look at the JVM class loading mechanismThe bytecode execution engine is used to actually execute Java bytecode. The JVM memory model is divided into the following parts:

Threads share

  • Heap: Stores new objects
  • Method area (meta space, permanent generation) : constant pool, static variables, class meta information

Thread exclusive

  • Stack (thread stack, virtual machine stack) : Stores local variables for each thread
  • Local method stack: Stores Java native methods
  • Program counter: Records where thread methods are running

The stack

A stack, also known as a virtual machine stack or thread stack, is probably more straightforward. Let’s start with a simple piece of code:

package think_in_jvm;

public class JvmDemoTest {
    
    private  void calculation(a){
        int a=2;
        int b=3;
        int c=(a+b)*10;
    }
    
    public static void main(String[] args) {
        JvmDemoTest jvmDemoTest=new JvmDemoTest();
        jvmDemoTest.calculation();
        System.out.println("hello jvm"); }}Copy the code

When the code above runs, it starts a thread running main, and the JVM allocates a block of memory on the stack for it to store data, so the JVM actually allocates a block on the stack for each running threadStack memory spaceEach time a method is executed, a block of memory is allocated to that methodStack frame memory spaceThe local variables used to store each method are structured like stacks in our data structures, with stack frames pushed first and released later. Stack frame memory space is divided into: local variable table, operand stack, dynamic link, method exit. And each thread has a uniqueProgram counterTo record the current code execution location, and a store of local methodsLocal method stack Disassemble the class using javap commands, and you get a command file that is more readable than Java bytecode

javap -c -p JvmDemoTest.class > JvmDemoTest.txt
Copy the code
Compiled from "JvmDemoTest.java"
public class think_in_jvm.JvmDemoTest {
  public think_in_jvm.JvmDemoTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  private int calculation(a);
    Code:
       0: iconst_2
       1: istore_1
       2: iconst_3
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: bipush        10
       9: imul
      10: istore_3
      11: iload_3
      12: ireturn

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class think_in_jvm/JvmDemoTest
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokespecial #4                  // Method calculation:()I
      12: istore_2
      13: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      16: new           #6                  // class java/lang/StringBuilder
      19: dup
      20: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
      23: ldc           #8                  // String hello jvm
      25: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;) Ljava/lang/StringBuilder;
      28: iload_2
      29: invokevirtual #10                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      32: invokevirtual #11                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      35: invokevirtual #12                 // Method java/io/PrintStream.println:(Ljava/lang/String;) V
      38: return
}
Copy the code

Related instruction meaning can refer to the following link, this detailed analysis of the following calculation () execution docs.oracle.com/javase/spec… www.jianshu.com/p/190e94e31…

private int calculation(a);
    Code:
       0: iconst_2 willintType constants2Push the operand stack1: istore_1 pushes operands to the top of the stackintThe value is stored in the control1Local variables (i.e. a=2Put in local variable table)2: iconst_3 willintType constants3Push the operand stack3: istore_2 pushes operands to the top of the stackintThe value is stored in the control2Local variables (i.e. b=3Put in local variable table)4: iload_1 will be the first1intLocal variables are pushed onto the operand stack5: iload_2 will be the first2intLocal variables are pushed onto the operand stack6: iadd adds the two values at the top of the operand stack and stores the result back to the top of the stack7: bipush        10constant10Push the operand stack9Imul multiplies the two values at the top of the operand stack and restores the result to the top of the operand stack10: istore_3 pushes the operand to the top of the stackintThe value is stored in the control3Local variables (i.e. C =50Put in local variable table)11: iload_3 will be the first3intLocal variables are pushed onto the operand stack12: ireturn Returns the current methodint
Copy the code

The operand stack and the table of local variables have been made clear by the above execution instruction parsing of the Calculation method. All of our logarithmic operations are going to be pushed inThe operand stackFinally out of the stack to the CPU register execution, whileLocal variable scaleIt’s going to store all the local variables of the method, whereas for our new object it’s going to store inThe heapA local variable in the stack stores its address or reference in the heap, as does a static member variable in a meta space.So the so-calledDynamic linkThat is, at run timeSymbolic referenceInto aDirect reference. Can be understood as a direct memory pointer to the address where the code is storedSymbolic referenceInto aDirect referenceWhile static methods are similar to main() methods, non-static methods need to be dynamically linked at run time. The Calculation () method in the following code requires dynamic linking

   public static void main(String[] args) {
        JvmDemoTest jvmDemoTest=new JvmDemoTest();
        int s=jvmDemoTest.calculation();
        System.out.println("hello jvm"+s);
    }
Copy the code

The method exit records where the method returns to the main method after its final execution. To sum up:

  1. Local variable table: Stores method local variables
  2. Operand stack: Stores data that needs to be manipulated
  3. Dynamic linking: The runtime converts symbolic references to direct references
  4. Method exit: Store record method exit, which is where the code runs after the method ends.

The heap

The heap side is mainly divided into three parts to illustrate

  1. Partition of heap memory region
  2. Heap memory flow model
  3. GC ROOT and STW mechanisms
1. Divide the heap memory area

The heap is further divided into:Eden district, Survivor district and old age. Eden and Survivor zones are also known as young generations, so there is a concept of generation. By default, the young generation accounts for 1/3 of the total heap memory, while the old generation accounts for 2/3. The ratio of Eden zone and Survivor zone is 8:2, while Survivor zone is divided into S0 and S1. There will be a process of object transfer, and the ratio is 1:1. The objects of the younger generation belong to thatTowards the evening’s deathObject, and the old age object isThere for a long timeGarbage collection is also divided into minor or young gc, which collects objects from the younger generation, and full GC, which collects objects from the entire heap, including objects from the younger generation and older generations.

2. Heap memory flow model

When Eden is full, minor GC, also called young GC, will be triggered. At this time, objects of the young generation will be garbage collected. The garbage collection thread started by the bytecode execution engine will first look for GC ROOT in the heap, stack, meta-space, and local method stack and mark all objects referenced by GC ROOT. The remaining objects are garbage objects. The garbage objects are removed directly and the surviving objects are moved to survivor zone. If the object already in survivor zone still survives, it will increase the generation age and circulate in S0 zone and S1 zone. When the generation age reaches 15, the object will be put into the old age for long-term preservation. The full GC is triggered to perform a full garbage collection of heap memory and meta space when the old decade space is full, which takes longer STW than the minor GC. When full GC after old age.

Using Java’s own JVisualVM tool, you can see the flow of the entire heap memory. The OOM example code is as follows

package think_in_jvm;

import java.util.ArrayList;
import java.util.List;

// Heap memory flow test
public class JvmHeapCirculation {

    private static Integer count=0;

    private byte[][] a=new byte[10] [1024];



    public static void main(String[] args) throws InterruptedException {
        List<JvmHeapCirculation> list=new ArrayList<>(16);
        while (true){
            list.add(new JvmHeapCirculation());
            Thread.sleep(10); }}}Copy the code

List

List =new ArrayList<>(16); -xms150m -xmx150m set the heap size to 150M. Objects added to the loop by GC ROOT will be referenced until OOM.

STW stops The World, which means that during garbage collection, The GC will Stop The user threads from running. All non-garbage collection threads will be suspended and stopped.

General model of JVM parameter setting

General Settings are as follows (the actual situation can be dynamically adjusted according to the server) :

java -Xms2048M -Xmn2048M -Xmn1024M -Xss512K -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -jar server.jar
Copy the code

Generally, the initial size and the maximum size are set to the same value to avoid expansion costs. In particular, for the meta space, if no value is set, the default value is -1. The size is limited only by the size of the physical memory, and the initial value is 21 MB. Its capacity expansion requires full GC, which is a significant overhead.