This is the sixth day of my participation in the August More text Challenge. For details, see:August is more challenging

Then we have a thorough understanding of the second link is the JVM memory structure, a lot of people want to go to BAT and other companies for the interview, but now the Internet giant interview assessment of almost all the JVM the accumulation of knowledge, where after understanding over the JVM class loading mechanism, it is necessary for us to learn together under the JVM memory area.

Through the class loading process in fact, we can also know that, in preparation for our class, and the distribution of the static variables are space, the JVM when we run the code, is a must to use the piece of memory space, different space which contain different data, and then cooperate with our code flow, the operation of the complete system.

5.1 Program counter

First, let’s look at the first area of memory: program counters

Program Counter Register

  • To remember where the next JVM instruction will be executed
  • The characteristics of
    • Is thread private
    • There will be no memory overflow

Let’s start with a very simple piece of code:

public class Demo1 {
    public static void main(String[] args) {
        int num1 = 1;
        System.out.println(num1);
        int num2 = 2; System.out.println(num2); }}Copy the code

Everyone can understand this code, but can the JVM understand it? The answer is: NO!

The JVM is not recognition we write the code, we will be compiled to the Java code. The class bytecode file, and the code is in the bytecode file can identify the JVM and executed, the code we also call “bytecode instruction”, it corresponds to a a machine instructions, the JVM by these instructions explain translation into machine instructions, To manipulate our calculator to execute.

The above code corresponds to the following bytecode instructions:

 0 iconst_1
 1 istore_1
 2 getstatic #2 <java/lang/System.out>
 5 iload_1
 6 invokevirtual #3 <java/io/PrintStream.println>
 9 iconst_2
10 istore_2
11 getstatic #2 <java/lang/System.out>
14 iload_2
15 invokevirtual #3 <java/io/PrintStream.println>
18 return
Copy the code

The specific instruction meaning will be explained later, but we need to know that the [program counter] is to record the address of a JVM to execute instructions

Represented by the previous load diagram:

5.2 VM Stack

define

Java Virtual Machine Stacks

  • The memory required for each thread to run is called the virtual machine stack
  • Each stack consists of multiple stack frames, corresponding to the memory used for each method call
  • Each thread can have only one active stack frame, which corresponds to which method is currently executing
explain

1. The memory required for each thread to run is called the virtual machine stack –> Each thread has its own Java virtual machine stack

Java code must be executed by a thread. Even our main() method has a main thread. When the main thread executes the instructions of the main() method, it records the location of the instructions by the corresponding program counter of the main thread.

The main() method is essentially a method. Other methods can be called from main(), and each method has its own local variable data. Therefore, the JVM provides an area of memory to hold data such as local variables within each method, called the Java Virtual Machine stack.

2. Each stack consists of multiple stack frames, which correspond to the memory occupied by each method call

When we call a method in a thread, we create a stack frame for that method, as shown in our code:

public class Demo1 {
    public static void main(String[] args) {
        int num1 = 1;
        System.out.println(num1);
        int num2 = 2; System.out.println(num2); }}Copy the code

In this case, the stack frame corresponding to the main method is created in the memory of the vm stack, and the corresponding local variable is recorded and saved:

If we call another method in the main() method:

public class Demo1 {
    public static void main(String[] args) {
        int num1 = 1;
        System.out.println(num1);
        int num2 = 2;
        System.out.println(num2);
        method1();
    }

    public static void method1(a){
        int num3 = 20;
        System.out.println("Ha ha ha ha"); }}Copy the code

The corresponding VM stack:

When method1 finishes executing, the stack queue pops up, and finally the main() stack frame pops up, indicating that the entire main method code is executed. This also corresponds to the characteristics of the stack: advanced after out.

Summary of flow chart:


Stack memory related interview case analysis
  1. Does garbage collection involve stack memory?

    The stack frame automatically boundles the stack at the end of each execution, so there is no garbage generation involved, and the stack memory is not garbage collected

  2. The larger the stack memory allocation, the better?

    No, if the physical memory allocated is 100MB and the thread stack size is 1MB, then 100 threads can be allocated, but if the thread stack size is increased, the corresponding number of threads can be allocated is reduced.

    Let’s look at the default size allocation for each stack frame given by the official website:

The default is 1MB on Linux, but we can change the size by -xss

  1. Are local variables within methods thread-safe?

    • A method is thread-safe if its local variables are not accessed by escaping the function of the method
    • If a local variable references an object and escapes the scope of a method, you need to consider thread-safety

    Refer to the following example code:

      // Local variables within methods: thread safe
        public static void method1(a){
            StringBuilder sb = new StringBuilder();
            sb.append(1);
            sb.append(2);
            sb.append(3);
            System.out.println(sb);
        }
        // Local variables reference objects within methods: thread unsafe
        public static void method2(StringBuilder sb){
            sb.append(1);
            sb.append(2);
            sb.append(3);
            System.out.println(sb);
        }
        // Local variable reference objects within methods provide exposure: thread unsafe
        public static StringBuilder method3(a){
            StringBuilder sb = new StringBuilder();
            sb.append(1);
            sb.append(2);
            sb.append(3);
            return sb;
        }
    Copy the code
  2. Stack memory overflow

    What causes Stack Overflow

    1) Too many stack frames cause memory overflow, and StackOverflowError is thrown.

A common case is a recursive call that keeps producing new stack frames without releasing the previous stack frames

We can test and experiment with the following code:

/ * * *@Description: VM Args: -xSS128K For different Versions of Java virtual machines and operating systems, the minimum stack size may be limited, depending on the operating system memory page size. For example, the -xss128k parameter can be used normally for JDK 6 on 32-bit Windows, but if used for JDK 11 on 64-bit Windows, it will prompt that the minimum stack size must be 180K. On Linux, the value may be 228K. The Java thread stack size specified is too small. Specify at least 228k */
public class JavaVMStackSOF {
    private int stackLength = 1;
    public void stackLeak(a) {
        stackLength++;
        stackLeak();
    }
    public static void main(String[] args) throws Throwable {
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try {
            oom.stackLeak();
        } catch (Throwable e) {
            System.out.println("stack length:" + oom.stackLength);
            throwe; }}}Copy the code

Print result:

2) The stack frame is too large, resulting in memory overflow, and StackOverflowError will be raised.

This time we can try to make the local variables of each stack frame take up a little more space, so that the size of each stack frame will be larger. Let’s set the stack space to 128K per thread again, and see how many times the following code runs:

/ * * *@Description: VM Args: -Xss128k
 */
public class JavaVMStackSOF2 {
    private static int stackLength = 0;
    public static void test(a) {
        long unused1, unused2, unused3, unused4, unused5,
                unused6, unused7, unused8, unused9, unused10,
                unused11, unused12, unused13, unused14, unused15,
                unused16, unused17, unused18, unused19, unused20,
                unused21, unused22, unused23, unused24, unused25,
                unused26, unused27, unused28, unused29, unused30,
                unused31, unused32, unused33, unused34, unused35,
                unused36, unused37, unused38, unused39, unused40,
                unused41, unused42, unused43, unused44, unused45,
                unused46, unused47, unused48, unused49, unused50,
                unused51, unused52, unused53, unused54, unused55,
                unused56, unused57, unused58, unused59, unused60,
                unused61, unused62, unused63, unused64, unused65,
                unused66, unused67, unused68, unused69, unused70,
                unused71, unused72, unused73, unused74, unused75,
                unused76, unused77, unused78, unused79, unused80,
                unused81, unused82, unused83, unused84, unused85,
                unused86, unused87, unused88, unused89, unused90,
                unused91, unused92, unused93, unused94, unused95,
                unused96, unused97, unused98, unused99, unused100;
        stackLength++;
        test();
    }

    public static void main(String[] args) throws Throwable {
        try {
            test();
        }catch (Error e){
            System.out.println("stack length:" + stackLength);
            throwe; }}}Copy the code

Print result:

We only found 51 times to burst!

Summary:

Whether because the stack frame is too large or the virtual machine stack is too small, the HotSpot virtual machine will always throw a StackOverflowError exception when new stack frame memory cannot be allocated.