An overview of the

During the execution of a Java program, the Java virtual machine divides all of its memory into several data areas, which have their own purposes and creation and destruction times. Some are created when the virtual machine is started, and some are created and destroyed when the user’s thread is started and terminated. Six zones are defined according to the Java Virtual Machine Specification

1. PC Register or program counter (The PC Register)

1.1 illustrates

The Program Counter Register is a small memory space that can be thought of as a line number indicator of the bytecode executed by the current thread. Basic functions such as branching, looping, jumping, exception handling, thread recovery, and so on rely on this counter.

  • Stores the line number indicator of the bytecode executed by the current thread
  • Each thread has an independent program counter that does not affect each other
  • If the thread executes a Java method, the counter records the address of the virtual machine bytecode instruction being executed
  • If the local method is executing, this counter value should be null (undefined)
  • The only area in the runtime data area that does not appear in OOM has no garbage collection

1.2 Code Demo

1.3 Common Problems

  • 1. What is the use of using PC registers to store byte code instruction addresses? Why use a PC register to record the execution address of the current thread? A: Because the CPU is constantly switching threads, it needs to know where to start after switching back. The JVM’s bytecode interpreter needs to change the value of the PC register to determine what bytecode instructions to execute next
  • 2.PC register why will be set as thread private we all know the so-called multi-threading in a specific period of time refers to the execution of a thread of the method, the CPU will keep drips do task switching, so will inevitably lead to frequent interruption or recovery, how to ensure that there is no difference? In order to accurately record the address of the current bytecode instructions being executed by each thread, it is naturally best to assign each thread a PC register so that each thread can compute independently without interfering with each other. Due to the CPU time wheel limit, a single processor or core of a multi-core processor will execute only one instruction in a particular thread at any given time during the concurrent execution of multiple threads. This will inevitably lead to frequent interruptions or recovery, how to ensure that there is no difference? After each thread is created, it will generate its own program counter and stack frame. Program counter does not affect each thread.

1.4 CPU Time slice

The CPU time slice is the time that the CPU allocates to each program. Each thread is allocated a time slice. It’s called its time slice. On a macro level: we can have multiple applications open at the same time, each running in parallel. But on a micro level: since there is only one CPU and only a portion of the program’s requirements can be processed at a time, one way to deal with fairness is to introduce time slices that each program executes in turn. Parallel and concurrent parallelism: multiple threads are executing simultaneously; Concurrency: A core quickly switches multiple threads so that they execute in sequence, which looks like parallelism but is actually concurrency

2. Java Virtual Machine Stacks

2.1 illustrates

Java Virtual Machine Stacks are thread-private and have the same lifetime as a thread. The virtual machine Stack describes the memory model of Java method execution: a Stack Frame is created for each method execution, storing local variables, operation stacks, dynamic links, and method exits. Each method called to the completion of the execution process, corresponding to a stack frame in the virtual machine stack from the process.

  • Java Virtual Machine Stack (Java Virtual Machine Stack), also known as the Java Stack. Each thread creates a virtual machine Stack, which holds Stack frames for each Java method call. It is thread private
  • Manages the execution of a Java program, which holds local variables of a method (eight basic data types, reference addresses of objects), partial results, and participates in method calls and returns.
  • The lifecycle is consistent with threads

2.1.1 Heap and stack in memory

  • The stack is the unit of runtime, and the heap is the unit of storage: the stack solves the problem of how programs run, how programs execute, or how they process data. The heap solves the problem of data storage — how and where data is stored.
  • In general, objects are mostly in heap space, a large part of the run-time data area
  • Stack space holds local variables of the base data type and references to objects that reference the data type

2.1.2 Stack operation

  • Stack is a fast and efficient way to allocate storage, second only to PC registers (program counters) in access speed
  • The JVM has only two direct operations on the Java stack
    • Each method executes with a push (push, push)
    • Each method executes with a push (push, push)
  • There is no garbage collection problem for the stack

2.1.3 stack OOM

The Java Virtual Machine specification allows the size of the Java stack to be dynamic or fixed

  • With a fixed size Java virtual machine stack, the size of the Java virtual machine stack for each thread can be selected independently at thread creation time. The Java virtual machine will throw a StackOverFlowError if the thread request allocates more stack capacity than the maximum allowed by the Java virtual machine stack
  • The Java virtual machine will throw an OutOfMemoryError if the Java virtual machine stack can expand dynamically and cannot claim enough memory when attempting to expand, or if there is not enough memory to create the corresponding virtual machine stack when creating a new thread
Public class StackErrorTest {public static void main(String[] args) {main(args); }}Copy the code

2.1.4 Setting stack size Parameters

Use the -xSS option to set the maximum stack size for a thread. The stack size directly determines the maximum reachable depth of a function call.

/** * display stack exception ** Default: count 10818 * set stack size:  -Xss256k count 1872 */ public class StackErrorTest { private static int count = 1; public static void main(String[] args) { System.out.println(count); count++; main(args); }}Copy the code

2.2 Interior and operation of stack

2.2.1 Stack description

  • Each thread has its own Stack, and the data in the Stack is stored in the format of Stack frames
  • Each method being executed on this thread corresponds to its own stack frame
  • A stack frame is a block of memory, a data set that holds various data information during the execution of a method
  • The JVM operates directly on the Java stack only two times, namely, on and off the stack frame, following the principle of fifo/LIFO and fifO.
  • In an active thread, there is only one active stack frame at a time. That is, only the stack Frame (top stack Frame) of the currently executing method is valid. This stack Frame is called the Current Frame, and the corresponding method is the Current Frame.
  • All bytecode instructions run by the execution engine operate only on the current stack frame
  • If another method is called in this method, a new stack frame is created and placed at the top of the stack as the new current stack frame
  • The stack frames contained in different threads are not allowed to reference each other, that is, it is impossible to reference another thread’s stack frame in another stack frame
  • If the current method calls another method, when the method returns, the current stack frame will return the execution result of this method to the previous stack frame, and then the virtual machine will discard the current stack frame, making the previous stack frame become the current stack frame again
  • Java methods have two ways of returning functions. One is to return a normal function using a return directive. The other is to throw an exception. Either way, the stack frame will be ejected.

Public StackFrameTest {public static void main(String[] args) {public static void main(String[] args) {StackFrameTesttest= new StackFrameTest(); test.method1(); Output method1() and method2 () both appear twice as current stack frames, and method3 () once // method1() starts executing... // method2() starts executing... // method3() // method3() // method2() End... // method1() End... } public voidmethod1(){
        System.out.println("Method1 () starts executing...");
        method2();
        System.out.println("Method1 () completes execution...");
    }

    public int method2(){
        System.out.println("Method2 () starts executing...");
        int i = 10;
        int m = (int) method3();
        System.out.println("Method2 () completes execution...");
        return i+m;
    }

    public double method3(){
        System.out.println("Method3 () starts executing...");
        double j = 20.0;
        System.out.println("Method3 () Completes execution...");
        returnj; }}Copy the code

2.2.2 Internal structure of stack frames

  • Local Variables
  • Operand Stack (or expression Stack)
  • Dynamic Linking (or method reference that performs runtime constant pooling)
  • Method Return address (or definition of method normal or abnormal exit)
  • Some additional information

2.3 Local Variables

2.3.1 instructions

  • A local variable list is also called a local variable array or a local variable list
  • An array of numbers used to store method parameters and local variables defined in the method body. These data types include various basic data types, object references, and returnAddressleixing
  • Since the local variable table is built on the thread stack and is thread private data, there is no data security problem
  • The size required by the local variables table is determined at compile time and stored in the Maximum Local Variables data item in the Code attribute of the method. The size of the local variable scale does not change during method execution
  • The number of nested calls to a method is determined by the stack size. In general, the larger the stack, the more nested method calls. For a function, the more arguments and local variables it has, the larger the stack frame will be to meet the need for more information to be passed through method calls. In turn, function calls take up more stack space, resulting in fewer nested calls.
  • Variables in the local variable table are only valid in the current method call. During method execution, the virtual machine passes the parameter values to the parameter variable list using the local variable table. When the method call ends, the local variable table is destroyed along with the method stack frame.

2.3.2 Understanding and demonstrating variable Slot

  • Parameter values are always stored at index0 of the local variable array and end at the index of the array length -1
  • Local variable scale. The most basic storage unit is Slot.
  • Local variable table stores various basic data types (8 kinds), reference types and variables of returnAddress type known at compilation time.

    Byte, short, char, and float are converted to int before storage. Boolean is also converted to int, with 0 indicating false and non-0 indicating true.

    Long and double occupy both slots.
  • If you need to access the value of a 64bit local variable in the local variable table, you only need to use an index. (e.g., accessing a long or double variable)
  • If the current frame is created by a constructor or instance method, the object reference to this will be placed in slot with index 0, and the rest of the arguments will be sorted in the argument list.

public class LocalVariablesTest { private int count = 1; // Static methods cannot use this public static voidtestStatic(){// compile error because this variable does not exist in the local variable table of the current method!! System.out.println(this.count); }}Copy the code

2.3.3 Slot reuse

The slots in the local variable table in the stack frame can be reused. If a local variable goes out of its scope, the new local variable declared after its scope is likely to reuse the slots of the expired local variable, so as to achieve the purpose of saving resources.

private void test2() { int a = 0; { int b = 0; b = a+1; } int c = a+1; }Copy the code

2.3.4 Comparison and summary of static variables and local variables

  • According to data type:
    • Basic data types;
    • Reference data types;
  • By position declared in the class:
    • Member variables: They undergo default initialization assignments before being used
      • Assigning a default value to a class variable during the preparation stage of class loading and linking — assigning an explicit value to a class variable during initialization, i.e. assigning a static code block.
      • Not modified static: Instance variables: As the object is created, instance variable space is allocated in the heap space, with default assignment
    • Local variables: must be explicitly assigned before they can be used! Otherwise, the compilation fails
    • The part of the stack frame that is most relevant for performance tuning is the local variable table. When a method executes, the virtual machine uses a local variable table to complete the method’s delivery
    • Variables in the local variable table are also important garbage collection root nodes, as long as objects referenced directly or indirectly in the local variable table are not collected

2.4 Operand Stack

  • Each individual stack frame contains, in addition to the local variable table, a lifO operand stack, also known as an expression stack
  • Operand stack, in which data is written to or extracted from the stack according to bytecode instructions during the execution of a method, i.e. pushed or popped

Against 2.4.1 overview

  • The Java Virtual machine’s interpretation engine is a stack-based execution engine, where the stack is the operand stack
  • It is mainly used to store the intermediate results of the calculation process and serve as temporary storage space for variables in the calculation process
  • When a method is first executed, a new stack frame is created, and the operand stack of this method is empty
  • Each operand stack has an explicit stack depth for storing values, the maximum depth being defined at compile time
  • In a stack, 32bit types occupy one stack unit depth and 64bit types occupy two stack units depth
  • Instead of accessing the index, operand stack can only access the data once through the standard loading and unloading operations
  • If the called method has a return value, the return value is pushed into the operand stack of the current stack frame and updates the NEXT bytecode instruction to be executed in the PC register.
  • Let’s look at the execution process of a method (stack frame) by combining the above figure with the following figure. ② Store 15 and 15 into the local variable table

2.4.2 Difference between I ++ and ++ I

I ++ : use the I first, and then +1; ++ I: is the first I +1, and then take out the use;

2.4.3 ToS (Top-of-Stack Cashing)

  • The zero-address instructions used by stack-based virtual machines are more compact, but more loading and unloading instructions are required to complete an operation, which means more instruction dispatch times and memory read/write times
  • Because operands are stored in memory, frequent memory read/write operations inevitably affect execution speed. In order to solve this problem, the designers of HotSpot JVM have proposed the technology of stack top cache, which caches all the top of stack elements in the CPU registers in the house to reduce the number of reads/writes to memory and improve the execution efficiency of the epidemic

2.5 Dynamic Linking

2.5.1 overview

  • Each stack frame contains an internal reference to the run-time constant pool or to the method to which the stack frame belongs. The purpose of including this reference is to enable dynamic linking in code that supports the current method. Such as invokedynamic instructions
  • When a Java source file is compiled into a bytecode file, all variable and method references are kept in the class file’s constant pool as symbolic Refenrence. For example, describing a method that calls another method is represented by symbolic references to the method in the constant pool, so dynamic linking is used to convert these symbolic references to direct references to the calling method.

2.5.2 Method Invocation

  • The only task of a method call is to determine the version of the method being called (which method to call), not the actual running process inside the method
  • The process of compiling a Class file does not include the concatenation steps of a traditional compilation, and all method calls are stored in the Class file as symbolic references rather than the entry address of the method in the actual runtime memory layout. This makes Java powerful for dynamic extension, but it makes calling Java methods relatively complex, requiring direct references to target methods to be determined during class loading or even at runtime

In the JVM, the conversion of symbolic references to direct references to calling methods is related to the method binding mechanism

  • Static linking: when the target method of the call is known at compile time and the run time remains unchanged
  • Dynamic linking: Symbolic references to calling methods can only be converted into direct references during program runtime. Because this reference conversion process is dynamic, it is also called dynamic linking

The Binding mechanism of the corresponding method is Early Binding and Late Bingding.

  • Early binding: early binding is refers to the target method is invoked if at compile time, and the run-time remains the same, this method can be bound with subordinate type, as a result, due to clearly define the target method is called which one on earth is, therefore, you can use the static link way of converting symbols refer to reference directly.
  • Late binding (polymorphic) : If the called method cannot be determined at compile time, only the related method can be bound according to the actual type at run time. This method is called late binding.

2.5.3 Virtual methods and Non-virtual Methods

  • Non-virtual methods:
    • If the version of a method is specified at the compiler, that version is immutable at run time. Such methods are called non-virtual methods
    • Static methods, private methods, final methods, instance constructors, and superclass methods are all non-virtual
  • Other methods are called virtual methods

Which Java virtual machine calls bytecode instructions

  • Invokestatic: Invokes static methods
  • Invokespecial: Invoke instance constructor methods, private methods, and superclass methods
  • Invokevirtual: Calls all virtual methods
  • Invokeinterface: Invokes interface methods
  • Invokedynamic: Dynamically resolves the method to be invoked and executes it
  • The invokestatic and Invokespecial commands call non-virtual methods, and the rest (excluding final modifications) are virtual methods

Until the advent of Java8’s Lambda expressions, the generation of invokedynamic instructions, there was no direct generation in Java

/** * class Father {publicFather(){
        System.out.println("Father default constructor");
    }

    public static void showStatic(String s){
        System.out.println("Father show static"+s);
    }

    public final void showFinal(){
        System.out.println("Father show final");
    }

    public void showCommon(){
        System.out.println("Father show common");
    }

}

public class Son extends Father{
    public Son(){ super(); } public Son(int age){ this(); } public static void main(String[] args) { Son son = new Son(); son.show(); } public static void showStatic(String s){system.out.println (){system.out.println ();"Son show static"+s);
    }

    private void showPrivate(String s){
        System.out.println("Son show private"+s);
    }

    public void show(){
        //invokestatic
        showStatic(Big Head boy);
        //invokestatic
        super.showStatic(Big Head boy);
        //invokespecial
        showPrivate(" hello!"); //invokespecial super.showCommon(); //invokevirtual considers this method non-virtual because it declares that it has final and cannot be overridden by subclasses. //invokevirtual showCommon(); // Not explicitly adding super is considered virtual because subclasses may override showCommon info(); MethodInterfacein= null; In.methoda (); // InvokeInterface is not sure which interface implementation class to override in.methoda (); } public voidinfo(){

    }

}

interface MethodInterface {
    void methodA();
}
Copy the code

About the Invokedynamic instruction

  • The JVM bytecode instruction set was stable until Java 7 added an InvokeDynamic instruction, an improvement Java made for dynamic Typing Language support
  • However, java7 does not provide a way to generate invokedynamic instructions directly. You need to use ASM, the underlying bytecode tool, to generate invokedynamic instructions. It wasn’t until the advent of Java8’s Lambda expressions, the generation of invokedynamic instructions, that direct generation became available in Java
  • The dynamic language type support added in Java7 is essentially a change to the Java virtual machine specification, not to the Java language rules. This is a relatively complex area, and the most immediate benefit of the addition of method calls in the virtual machine is the dynamic language compiler running on Java credentials

Dynamically typed and statically typed languages

  • The difference between a dynamically typed language and a statically typed language is whether the type is checked at compile time or at run time. The former is statically typed and the other is dynamically typed
  • Java is statically typed (although lambda expressions add dynamic features to it), JS, and Python are dynamically typed

2.5.4 Nature of method rewriting

  • 1 Find the actual type of the object executed by the first element of the operand stack, called C.
  • 2. If a method in type C is found that matches the description in the constant with the simple name, the access permission is checked. If the method passes, the direct reference of the method is returned, and the search process is complete. If not through, it returns the Java. Lang. IllegalAccessError anomalies.
  • 3. Otherwise, search and verify each parent class of C from bottom to top according to the inheritance relationship.
  • 4. If didn’t find the right way, it throws the Java. Lang. AbstractMethodError anomalies. IllegalAccessError describes the application view accessing or modifying a property or calling a method that you do not have permission to access. Normally, this will cause a compiler exception. This error, if it occurs at run time, indicates an incompatible change to a class.

2.5.5 Virtual Method table

  • Object oriented programming, will be very frequent use dynamic allocation, if every time the process of dynamic allocation in the method of class metadata search again appropriate target, may affect the execution efficiency, so in order to improve the performance, the JVM area using the method of the class to build a virtual method table, using the index table instead of a search
  • Each class has a virtual method table that holds the actual entry to each method
  • So when is the virtual method table created? The virtual method table is created and initialized during the linking phase of the class load. After the class’s variable initializers are ready, the JVM initializes the class’s party table.

2.6 Method Return Address

  • Holds the value of the PC register that called the method
  • The end of the method is as follows: 1. The execution is completed normally. 2
  • Either way, when the method exits, it returns the location where the method was called. When a method exits normally, the value of the caller’s PC counter is returned as the address of the next instruction that calls the method.
  • If an exception exits, the return address is determined by the exception table. Generally, this part of information is not stored in the stack frame
  • In essence, the method exit is the process of the current stack frame out of the stack. At this point, it is necessary to restore the local variable table of the upper method, operand stack, return values such as the operand stack of the caller’s stack frame, set PC register values, etc., and let the caller’s method continue to execute.
  • The difference between a normal completion exit and an exception completion exit is that an exception completion exit does not return any value to its upper callers.
  • When the execution engine meets a bytecode instruction (return) from any method, the return value is passed to the upper method caller, referred to as the normal completion exit
    • Ireturn returns Boolean, byte, char, short, and int values
    • Areturn Indicates the reference type
    • There is also a return for methods declared as void, instance initializer methods, class and interface initializer methods

2.7 Additional Information

It allows you to carry additional information about Java virtual machine implementations, such as support for program debugging. Not sure. Optional

2.8 Common Problems

  • 1. Example stack overflow? (StackOverflowError) recursive calls, etc., via -xss to set stack size;

  • 2. Can stack size be adjusted to prevent overflow? It is not possible to overflow recursively for an infinite number of times, so adjusting the stack size only ensures that the overflow occurs later

  • 3. Is it better to allocate more stack memory? It doesn’t take up space for other threads

  • 4. Does garbage collection involve the virtual machine stack? Don’t

  • 5. Are local variables defined in methods thread-safe?

/** * Are local variables defined in methods thread-safe? What is thread-safe? * If only one thread can manipulate this data, the kill is thread-safe. * The data is shared if more than one thread operates on it. There are thread-safety issues if synchronization is not taken into account * * StringBuffers are thread-safe, */ public class StringBuilderTest {//s1 is declared in thread-safe public static voidmethod1(){
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b"); } //stringBuilder: Public static void method2(StringBuilder StringBuilder){stringBuilder.append("a");
        stringBuilder.append("b"); } public static StringBuilder public static StringBuilder public static StringBuilder public static StringBuildermethod3(){
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        returns1; } //s1 is thread-safe, StringBuilder toString creates a new String, s1 internally dies public static Stringmethod4(){
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        return s1.toString();
    }

    public static void main(String[] args) {
        StringBuilder s = new StringBuilder();
        new Thread(()->{
            s.append("a");
            s.append("b"); }).start(); method2(s); }}Copy the code

3 Local method stack

  • The Java virtual machine stack is used to manage the invocation of Java methods, and the local method stack is used to manage the invocation of local methods
  • The local method stack is also thread-private.
  • Allows memory sizes to be implemented as fixed or dynamically scalable. (Same in terms of memory overflow)
    • The Java virtual machine will throw a StackOverFlowError if the thread request allocates more stack capacity than the maximum allowed by the local method stack.
    • The Java virtual machine will throw an OutOfMemoryError if the local method stack can be extended dynamically and there is not enough memory to allocate when trying to extend it, or if there is not enough memory to create the corresponding local method stack when a new thread is created.
  • The native methods are implemented using the C language
  • It is implemented by registering Native methods in the Stack and loading the local Method library at Execution Engine time.
  • When a thread calls a local method, it enters a whole new world that is no longer constrained by the virtual machine. It has the same rights as the VIRTUAL machine
    • Local methods Access the runtime data area inside the virtual machine through the local method interface
    • It can even use the registers in the local processor directly
    • Allocate any amount of memory directly from the heap of local memory
  • Not all JVMS support native methods. Because the Java virtual Machine specification does not specify the language, implementation, data structure, and so on of the native method stack. If the JVM product does not intend to support native methods, you may not need to implement a native method stack.
  • In hotSpot JVM, the local method stack and virtual machine stack are combined directly.

4 Local method interface

  • To put it simply, a Native Method is a Java interface that calls non-Java code. A Native Method is a Java Method whose implementation is implemented by non-Java languages, such as C
  • The identifier Native can be used with all other Java identifiers except Abstract
  • Why use Native Method
    • Interact diplomatically with the Java environment: for example, start a thread
    • Interaction with the operating system: For example, when exchanging information with the underlying operating system or hardware