This article has participated in the activity of “New person creation Ceremony”, and started the road of digging gold creation together.

Memory structure

  1. Program counter
  2. The virtual machine stack
  3. Local method stack
  4. The heap
  5. Methods area

1. Program counter

The diagram above shows where the program counter is in the JVM, as it is part of the JVM memory structure.

1.1 define

Program Counter Register

Program is a Program, Counter is a Counter, and Register is not a direct translation, it means a Register, which we'll talk about later.Copy the code
  • Purpose: Remember the execution address of the next JVM instruction

  • Features:

    • Is thread private

      Java program is to support multithreading running together, multiple threads run together there will be a CPU to mobilize components to assign them time slices, such as to give a time slice thread 1, code it in time if it not performed, it will execute the thread 1 state a temporary, switch to the thread 2, code executing thread 2, When the code execution of thread 2 reaches a certain point and the time slice of thread 2 runs out, switch back and continue to execute the rest of the code of thread 1. Let's consider whether our program counter will still be used if the next instruction is executed during a thread switch. Each thread should have its own program counter because the instruction address of the code it executes is different.Copy the code
    • There will be no memory overflow

      The program counter is the only area in the Java virtual Machine specification that does not run out of memory. Other areas, such as the heap, stack, and method areas, all run out of memory. The Java virtual machine specification stipulates that the program counter part has no memory overflow, so its various vendors of Java virtual machine implementation do not have to consider the program counter part of its memory overflow problem.Copy the code

1.2 role

The code on the right assigns system. out to a variable, and then calls the system. out println method to print 1, 2, and 3, which is some very simple Java code.

Java source code cannot be executed directly, it has to be compiled once, into the binary bytecode on our left, and the JVM instructions on the left, which are the foundation of the Java VIRTUAL machine across platforms and are consistent across all platforms. Can these instructions be handed directly to the CPU to execute? No, these instructions still can’t be handed to the CPU to execute, they have to go through an interpreter. This interpreter, which is also a component of the Java Virtual Machine execution engine, is responsible for interpreting each of our virtual machine instructions (such as getStatic) into machine code, and then handing the machine code to the CPU, which can execute it. The CPU only knows machine code.

Execution process:

The program counter is used to remember the execution address of the next JVM instruction

The execution flow plus the program counter looks like this: We get the first getStatic instruction, we give it to the interpreter, and the interpreter turns it into machine code and gives it to the CPU to run, but at the same time it puts the next instruction, astore_1, the address of the next instruction, which is 3, into our program counter, and when the first instruction is done, The interpreter then goes to the program counter to fetch the next instruction (astore_1 at address 3) and repeats the process. When 3 is executed, it will store the address of the next instruction (4) into the program counter. When 3 is finished, it will fetch the next instruction (4) from the program counter and repeat the process.

In short, the program counter is used to remember where the next JVM instruction will be executed (without this program counter, you wouldn’t know which JVM instruction to execute next). On the physical implementation of a program counter is done by register, the program counter is a Java for some of the physical hardware block and abstraction, in physics is done by register, register can be read CPU components is the fastest one unit, because reading instruction address this movement is very frequent, So the Java virtual machine is designed to treat the registers in our CPU as program counters, and use them to store addresses that can be read in the future.

2. Vm stack

We know that the stack is characterized by first in, last out.

So what does the virtual machine stack in Java really do? In Java, each thread needs to be allocated a memory space when running. In fact, our virtual machine stack is a memory space required by a thread to run. A thread running requires a virtual machine stack, and multiple threads running will have multiple virtual machine stacks. So what’s inside each stack? A stack can be viewed as consisting of multiple stack frames. What is a stack frame? In fact, a stack frame corresponds to a method call, so you think, my thread is ultimately going to execute code, and the code is made up of a method, so the memory that each method needs when the thread is running is called a stack frame. So the stack frame is the amount of memory that each method needs to run, so if you think about it, what kind of memory does a method need to run? Methods have parameters, local variables, and return addresses that take up memory, so we need to allocate memory beforehand for each method execution.

So how do stack frames relate to stacks?

For example, when the first method is called, it will allocate a segment of stack frame space for the first method and push it onto the stack. When the method is finished, it will remove the corresponding stack frame from the stack, which is to release the memory occupied by this method. This is the relationship between stack and stack frame.

Is it possible to have multiple stack frames in a stack?

The answer is yes, as I call the method 1, indirect method 1 and call the method 2, the method will be for 2 to create a new stack frame, method 2 and call the method 3, will be for method 3 to create a new stack frame, method invocation, there will always be an end of time, such as method 3 end of the call, it will release the stack frame 3 memory away, to return to the method 2, After method 2 is called, it will free up the memory occupied by method 2, and finally method 1 will free up the memory occupied by method 1, which is also out of the stack.

A stack (virtual machine stack) consists of multiple stack frames.

2.1 define

Java Virtual Machine Stacks

  • The amount of memory each thread needs to run is called the virtual machine stack.

  • Each virtual machine stack consists of multiple stack frames, and each stack Frame corresponds to the memory occupied by a method call.

  • Each thread can have only one active stack frame, corresponding to the method currently being executed.

    The active stack frame that represents the method that the thread is executing is called the active stack frame.Copy the code

The concepts of stack, stack frame, and active stack frame are clearly seen in the code below.

/** * demo stack frame */
public class Demo01 {
    public static void main(String[] args) throws InterruptedException{
        method01();
    }

    private static void method01(a){
        method02(1.2);
    }

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

To describe the process, we use the debug form to execute it:

First we execute the main method, which is also a method, and it also corresponds to a stack frame, which is put on the stack

Method01 () also has a stack frame, and it pushes the stack frame for method01() into the virtual machine stack, which we can see above the main method, which is also the stack structure

Moving down method01() calls method02(), the program assigns a stack frame to method2() and pushes the corresponding stack frame for methodo2() to the top of the virtual machine stack

When method02() is finished executing, the memory used by method02() is freed as its corresponding stack frame goes off the stack

Method01 () and the corresponding stack frame goes off the stack, and you’re back to the main method

The main method then executes and the whole program ends.

So that Frames corresponds to our Virtual machine stack in Java, and the virtual machine stack is made up of stack Frames, and the main method call, which is also a method, is just a stack frame memory, and it gets put on the stack, and then down it's going to call method01(), method01() needs some memory of its own, So we've allocated another stack frame to method01(), and we've pushed this new stack frame onto the stack, and you can see it's above main, and this is actually the stack structure, Method01 () calls method02(), and when we call method02(), we assign a stack frame to method02(), so we can see that the stack frame for method02() is at the top of the stack. You can see that the parameters to method02() and the internal local variables are taking up stack frame space, so what happens as you move down? Again go down method 2 is executed over, perform over method 2 memory will be released as the frame of the stack, you can see method 2 to take up the stack frame has been out of the stack, the amount of the local variables and parameters of the memory addresses are released, the same go down again, method01 () call to end a stack it went back to the main method, The main method then executes and the whole program ends. Note: The method executing at the top of the stack is called the active stack frame.Copy the code

The problem analysis

  1. Does garbage collection involve stack memory?

    No, why not? Since our stack memory is nothing more than the stack frame memory generated by each method call, and the stack frame memory is automatically reclaimed after each method call, there is no need for garbage collection to manage our stack memory. Garbage collection only collects garbage from heap memory, while stack memory does not and does not need to be garbage collected.Copy the code
  2. Is bigger stack allocation better?

    Stack memory can be specified by running code with a virtual machine parameter.

Does the bigger the stack, the faster the program runs? The answer is no, the larger the stack is, the smaller the number of threads is, because we have a certain amount of physical memory, let's say one thread is using stack memory, one thread is using 1M memory, and the total physical memory is 500 meters, so theoretically 500 threads can run at the same time, But if set up a 2 m for each thread's stack memory of memory, so in theory the most Can only be run at the same time 250 threads, so the stack memory not divide to the bigger the better, it divided into large, usually just can be more methods recursive call, rather than enhance operation efficiency, less it will affect the number of threads, Therefore, it is not recommended to set too large stack memory, generally use the system default stack memory size is ok.Copy the code
  1. Are local variables within a method thread-safe?
- If a local variable inside a method does not escape the scope of the method, it is thread-safe, whereas a local variable (a reference type variable) is returned as a return value, it is thread-safe and must be protected. If it is just a primitive type local variable, it is also guaranteed to be thread-safe. - If a local variable refers to an object and escapes the scope of a method, thread-safety concerns need to be considered. Markdown determines whether a variable is thread-safe. In fact, we need to determine whether the variable is shared by multiple threads or if the variable is private to each thread. If it is shared, we need to consider thread-safe. Public class Demo02 {static void method01(){int x = 0; for(int i = 0; i < 5000; i++){ x ++; } System.out.println(x); }} Because x is per-thread private, each thread has its own private X, there is no need to worry about thread-safety.Copy the code

` `

However, if we set x to static, then x is shared by multiple threads, and thread-safety concerns arise.Copy the code

`

Let’s move on to the next example:

   /** * thread safety issues with local variables */
   public class Demo03 {
       public static void main(String[] args) {
           StringBuilder sb = new StringBuilder();
           sb.append(4);
           sb.append(5);
           sb.append(6);
           new Thread(() -> {
               m2(sb);
           }).start();
       }
   
       /** * For the m1 method, if multiple threads execute the m1() method at the same time, there is no thread-safety problem * because the internal StringBuilder object sb is thread private, no other thread can access the StringBuilder object at the same time. So this method is thread-safe */
       public static void m1(a){
           StringBuilder sb = new StringBuilder();
           sb.append(1);
           sb.append(2);
           sb.append(3);
           System.out.println(sb.toString());
       }
   
       /** * m2() is not thread private because StringBuilder objects can be shared by multiple threads * so this method is not thread shared
       public static void m2(StringBuilder sb){
           sb.append(1);
           sb.append(2);
           sb.append(3);
           System.out.println(sb.toString());
       }
   
       The m3() method is not thread-safe. Although the StringBuilder object is a local variable in the method, the method returns it as the result of a string return, which means that other threads can take a reference to the thread and modify it concurrently, which can also cause thread-safe problems
       public static StringBuilder m3(a){
           StringBuilder sb = new StringBuilder();
           sb.append(1);
           sb.append(2);
           sb.append(3);
           System.out.println(sb.toString());
           returnsb; }}Copy the code

Conclusions can be drawn from the above analysis of thread safety problems of the three methods: To determine whether a variable is thread-safe, it is not only a local variable in a method, but also whether it escapes the scope of the method. If the variable escapes the scope of the method as a return value, it may be accessed by other threads and is no longer thread-safe.

2.2 Stack Memory Overflow

  • Too many stack frames cause stack memory overflow

    Stack size is fixed, a method is called after 1 frame 1 into the stack, in method 1 haven't finished call and then call the method 2, method 2 after finished call and then call the method 3, constant use, so has been into but not out of the stack, until some one call in frame memory than the entire stack memory, can not let go, cannot allocate a new stack frame is a memory, This can cause stack memory to run out. So you can think about what happens when you have so many stack frames? Is actually, in the case of a method of recursive call, if there are no set up the method in the recursive call a correct end conditions, it can lead to call themselves, and calls himself......, this call, each call to generate a stack frame, that even if the stack memory again big, also has run out of a day, So this will cause the stack to run out of memory error,Copy the code

  • Large stack frames cause stack memory overflow

    The problem of stack overflow caused by large stack frames is less likely to occur, because the variable of type int inside a method is only 4 bytes, and the stack memory is generally 1M, so it is very unlikely to occur.Copy the code

Here are a couple of scenarios where stack memory runs out using two specific examples:

Case 1:

/ * * * demo stack memory. Java lang. - Xss256k StackOverflowError * * * demonstration frame too much lead to stack memory * method1 () method calls himself, but did not set the recursive termination conditions, This will generate a new stack frame each time * is called, which will definitely exhaust the stack memory. * /
public class Demo04 {
    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++; method1(); }}Copy the code
/* The following result uses the default stack memory *Results: / Java. Lang. StackOverflowError / / stack of memory, Is an Error (Error) at the Memory. JVMstacks. Demo04. Method1 (Demo04. Java: 25) at the Memory. JVMstacks. Demo04. Method1 (Demo04. Java: 25) at Memory. JVMstacks. Demo04. Method1 (Demo04. Java: 25)...... / / that calls the 23252 times 23252 led to a stack of MemoryCopy the code

We can use the -xss256k vm parameter to set the stack size. We can set the stack size to be smaller to see if the recursion times of its method calls are reduced.

Open the running Settings of the application in IDEA

If you are using idea earlier, note that VM options may not appear later, so click here

Then check Add VM Options and the stack memory setting line will appear.

Then set the stack memory to 256K

Then we re-run the code, and we’ll see that we’re still running out of stack memory, but this time we’re only running through 3,000 times before we run out of stack memory, because we set the total stack size to be smaller.

java.lang.StackOverflowError at Memory.JVMstacks.Demo04.method1(Demo04.java:25) at Memory. JVMstacks. Demo04. Method1 (Demo04. Java: 25)...... 3863Copy the code

Case 2:

import java.util.Arrays;
import java.util.List;

/** * JSON data conversion */
public class Demo05 {
    public static void main(String[] args) {
        Dept d = new Dept();
        d.setName("Market");

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

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

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

        // Convert to json object
        // { name: 'Market', emps: [{ name: 'zhang', dept: { name:'', emps: [{}] } }] }  
        // Departments have employees, employees have departments, and so on
        ObjectMapper mapper = newObjectMapper(); System.out.println(mapper.writeValueAsString(d)); }}class Emp{
    private String name;
    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; }}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

The results of

Sometimes it's not the code you write that causes stack overflow. In this case, it's a loop reference between two classes that causes stack overflow during JSON parsing. How to solve this problem? Make sure to break the loop reference when converting json. For example, if you break it on one side, you can change the two-way management to one-way management by annotating @jsonIgnore. Employees are only managed by the department, and employees are no longer managed by the department.Copy the code

Let’s run it again after we modify the code

2.3 Thread Running diagnosis

Threads are related to the virtual stack, and here are a few examples of thread diagnostics to learn some useful tools.

Case 1: Excessive CPU usage

positioning

  • Run the top command to locate the process that consumes too many cpus
  • Ps – H – eo pid, dar, % CPU | grep process id (using the ps command further positioning which thread is high CPU usage)
  • Jstack process ID (tools provided with JDK)
    • You can locate the problematic thread based on the thread ID, and further locate the source line number of the problematic code
When an application is running, its CPU usage is high, so other programs are affected, which is a very dangerous signal. If the CPU usage of a program is higher than %90, it must be some code in the program has problems. Then how do we diagnose and troubleshoot these problems? So let's take a look.Copy the code

Run a Java program on a Linux VM and run the top command to monitor the CPU usage and memory usage of background processes

As you can see, there is one Java code that is taking up more than 97% of the CPU time, and all other programs are crowded out, and it is the only one that is constantly running on the CPU.

ps H -eo pid,tid,%cpu

The ps command displays the CPU usage of threads

H is to display all thread information in the process

The -eo argument specifies which content of interest to output

Pid follows -eo and indicates the output process ID

Tid indicates the id of the output thread

% CPU Displays the CPU usage

In this way, we can see the process IDS, thread ids, and CPU usage of all threads

If the number of threads is too high, because we know which process is causing the CPU usage to be too high

You can use:

ps H -eo pid,tid,%cpu | grep 32655

This 32655 is the ID of the process we have located that is using too much CPU

Use the jstack + process ID command (tools provided with JDK)

jstack 32655

Show all threads of process 32655

Process 32655 so many threads, how to check which thread has a problem?

Just now we have used ps command to locate the thread 32665 is faulty

The thread numbers printed with JStack are hexadecimal

The decimal 32665 is converted to hexadecimal 7F99

Open the Java code and find line 8

Case 2: The program runs for a long time with no results

Running the Java program should result in no result, perhaps a deadlock was found

Use jStack + process ID

So jStack 32752

Let’s take a look at the source code