The notes in this article are based on the JVM learning tutorial and the Small Drop Tutorial

  • Little drops of the classroom
  • Pass the wisdom podcast Billie Billie link

Introduction to JVM

The JVM is defined

Java Virtual Machine, Java program run environment (Java binary bytecode run environment)

The JVM advantage

  • Write it once, run it anywhere
  • Automatic memory management, garbage collection mechanism
  • Array subscript out of bounds check

Common JVM

Note: We use the HotSpot version for our notes

JVM JRE JDK comparison

JVM JRE JDK differences:

Learning step

The learning sequence is shown below :(from simple to difficult)

Second, memory structure

The overall architecture

1. Program counter (register)

Program Counter Register

1.1 role

The program counter is used to hold the address of the next instruction to be executed in the JVM

0:getstatic #20 					 // PrintStream out = System.out;
1:astore_1 							// --
2:aload_1 							// out.println(1);
3:iconst_1 							// --
4:invokevirtual #26 				 // --
5:aload_1 						    // out.println(2);
6:iconst_2 							// --
7:invokevirtual #26 				 // --
8:aload_1 						    // out.println(3);
9:iconst_3 						    // --
10:invokevirtual #26 				 // --
11:aload_1 							// out.println(4);
12:iconst_4 						// --
13:invokevirtual #26 				 // --
14:aload_1 						    // out.println(5);
15:iconst_5 						// --
16:invokevirtual #26 				 // --
return
Copy the code

Java instruction execution process:

  • Each binary bytecode (JVM instruction) is converted into machine code by the interpreter and then executed by the CPU!
  • When the interpreter converts a JVM instruction into machine code, it submits the address of the execution of the next JVM instruction to the program counter!
  • The program counter is actually implemented through registers at the hardware level!
  • So the program counter is used to hold the address of the next instruction to be executed in the JVM!

1.2 the characteristics of

  • Thread private

    • The CPU allocates time slices for each thread, and when the previous thread runs out of time slices, the CPU executes code in another thread
    • The program counter is private to each thread. When another thread runs out of time and returns to execute the current thread’s code, the program counter lets you know which instruction to execute
  • There will be no memory overflow

2. Virtual machine stack

Java Virtual Machine Stacks

2.1 define

  • The amount of memory required for each thread to run is called the virtual machine stack (Frames)
  • Each stack consists of multiple stack frames, corresponding to the memory occupied by each method at runtime
  • Each thread can have only one active stack frame, corresponding to the currently executing method, which is pushed when the method is executing and ejected when the method is finished

2.2 presentation

code

/ * * *@Auther: csp1999
 * @Date: 2020/11/10 / hand *@Description: Demo stack frame */
public class Demo01 {
    public static void main(String[] args) {
        methodA();
    }

    private static void methodA(a) {
        methodB(1.2);
    }

    private static int methodB(int a, int b) {
        int c = a + b;
        returnc; }}Copy the code

Let’s interrupt to Debug to see how the method executes:

Then proceed down to make method B complete:

Then, after the execution of method A, its corresponding stack frame is out of the stack, and the corresponding stack frame of main method is active stack frame; Finally, main completes the stack frame out of the stack, virtual machine stack is empty, the end of the code run!

2.3 Analysis of interview questions

  • 1. Does garbage collection involve stack memory?

    • Don’t need. Because the virtual machine stack is composed of stack frames, the corresponding stack frame will be removed from the stack after the method is executed. There is no need to recycle memory through garbage collection.
  • 2. Is the larger stack memory allocation the better?

    • It isn’t. Because physical memory is fixed, the larger the stack memory, the more recursive calls it can support, but the fewer threads it can execute.
    • For example, if the physical memory is 500 MB (let’s say), and if the stack memory allocated by one thread is 2 MB, then there could be 250 threads. If one thread allocates 5M of stack memory, then at most 100 threads can execute simultaneously!
  • 3. Are local variables in methods thread-safe?



    It follows from the diagram that local variables that are static and can be shared by multiple threads are thread-safe. If it is non-static and only exists in the scope of a method and is private to the thread, then it is thread-safe!

Look at an example:

/** * thread safety issues with local variables */
public class Demo02 {
    public static void main(String[] args) {// the main thread of the main function
        StringBuilder sb = new StringBuilder();
        sb.append(4);
        sb.append(5);
        sb.append(6);
        new Thread(() -> {// Thread Indicates the newly created Thread
            m2(sb);
        }).start();
    }

    public static void m1(a) {
        // sb, as a local variable inside method m1(), is thread-private --> thread-safe
        StringBuilder sb = new StringBuilder();
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
    }

    public static void m2(StringBuilder sb) {
        // sb is passed to method m2() outside the scope of method m2(
        // Not thread-private --> not thread-safe
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
    }

    public static StringBuilder m3(a) {
        // sb is a local variable inside method m3() that is thread private
        StringBuilder sb = new StringBuilder();// sb is a variable of reference type
        sb.append(1);
        sb.append(2);
        sb.append(3);
        return sb;// While method m3() returns sb, sb escapes the scope of method m3() and sb is a variable of reference type
        // Other threads can also get this variable's --> non-thread-safe
        
        // If sb is a non-reference type, that is, a basic type (int/char/float...) Variables, out of m3() scope, there is no thread safety}}Copy the code

Answer to the interview question:

  • Local variables within a method are thread-safe if they do not escape the scope of the method
  • If a local variable references an object and escapes the scope of a method, thread-safety concerns need to be considered

2.4 Memory Overflow

Java. Lang. StackOverflowError stack memory

causes

  • 1. Too many stack frames (infinite recursion) in the virtual machine stack, which is quite common!
  • 2. The memory occupied by each stack frame is too large (the memory of one or several stack frames directly exceeds the maximum memory of the virtual machine stack), which is rare!

Here are two examples:

Case 1:

/ * * * demo stack memory Java. Lang, StackOverflowError * - Xss256k can memory parameters setting stack memory size * /
public class Demo03 {
    private static int count;

    public static void main(String[] args) {
        try {
            method1();
        } catch(Throwable e) { e.printStackTrace(); System.out.println(count); }}private static void method1(a) {
        count++;// Count stack frames
        method1();// The method is infinitely recursive, continually generating stack frames to the virtual machine stack}} last output: Java. Lang. StackOverflowError ats com. Haust. Jvm_study. Demo. Demo03. Method1 (Demo03. Java:21)... .39317// Number of stack frames. Different VM sizes can store different stack frames
Copy the code

We can modify the parameters to specify the vm stack memory size

When we run Demo03 after reducing the vm stack memory to 256K, we will get the maximum stack frame number: 3816 is much smaller than the original 39317!

Case 2:

/** * Stack overflow ** solution: Break the loop by ignoring the DEPT property in the employee EMP and placing recursive calls to each other */
public class Demo04 {

    public static void main(String[] args) throws JsonProcessingException {
        Dept d = new Dept();
        d.setName("Market");

        Emp e1 = new Emp();
        e1.setName("csp");
        e1.setDept(d);

        Emp e2 = new Emp();
        e2.setName("hzw");
        e2.setDept(d);

        d.setEmps(Arrays.asList(e1, e2));

        / / output results: {" name ":" Market ", "emps" : [{" name ":" CSP "}, {" name ":" HZW}]}
        ObjectMapper mapper = new ObjectMapper();// Import the Jackson packageSystem.out.println(mapper.writeValueAsString(d)); }}/** * employee */
class Emp {
    private String name;
    @JsonIgnore// Ignore this property: why? Let's analyze it!
    / * * * if we don't ignore employees department attributes of object * System. Out. The println (mapper. WriteValueAsString (d)); * {* "name":"Market","emps": C * * [{" name ":" CSP, "dept: {name: 'XXX', emps: '... '}}, *... *] *} * in other words, the output, the department dept json string contained in the employee object emp, * The emP contains dept, so the json string gets longer and longer. * Until the stack overflows! * /
    private Dept dept;

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Dept getDept(a) {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept; }}/** ** department */
class Dept {
    private String name;
    private List<Emp> emps;

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Emp> getEmps(a) {
        return emps;
    }

    public void setEmps(List<Emp> emps) {
        this.emps = emps; }}Copy the code

2.5 Thread Running diagnosis

Case 1: The CPU usage is too high

  • In Linux, some programs may occupy too much CPU. In this case, locate the threads that occupy too much CPU

    • The top command is used to check which process occupies too much CPU



    • Ps H – eo pid, dar (thread id), % CPU | grep just through the top number to check the process Through the ps command to view the details of which thread CPU is too high!

    • Jstack process ID You can view the NID of the thread in the process and the TID displayed by using the ps command to locate the process. Note that the jstack process ID is in hexadecimal format and needs to be converted

      • You can use the thread ID to find the thread with the problem, and further locate the number of source lines of the problem code!



As you can see, thread1 is running in the runnable thread above, indicating that it consumes a lot of CPU memory.



3. Local method stack

Some methods with native keywords require JAVA to call native C or C++ methods, because JAVA sometimes cannot directly interact with the underlying operating system, so you need to use native methods!

As shown in figure:



  • The function of the local interface is to integrate different programming languages for Java, and its original intention is to integrate C/C++ programs. When Java was born, C/C++ was running wild. To get a foothold, C/C++ programs had to be called The ive Method Stack registers native methods and loads the Native Libraies during Execution by the Execution Engine
  • This approach is now used less and less, except for hardware-related applications, such as Java programs driving printers or Java systems managing production equipment, which are rare in enterprise applications. Because the communication between heterogeneous domains is very developed, for example, Socket communication can be used, Web Service can also be used, and so on, I will not introduce
  • Native Method Stack (Native Method Stack) Native Method Stack (Native Method Stack) Native Method Stack (Native Method Stack)
  • Examples of native methods: The Clone Wait Notify hashCode and other broadening classes in the Object class are native methods