This is the 31st day of my participation in the August More Text Challenge

Phase to recommend

  • Java Basics
  • Java concurrent programming
  • JVM

1. Overview of runtime data area and threads

1.1 Runtime data area structure

This section focuses on the runtime data area, which is shown in the following figure, after the class has been loaded.

As we pass the previous: classloading— – >validation— – >To prepare— – >parsing— – >Initialize theWhen these phases are complete, the execution engine will use our class, and the execution engine will use usRuntime data area.

1.1.1 Runtime data area and memory

  1. Memory is a very important system resource, yesThe hard diskandCPUThe intermediate warehouse and bridge, carrying the real-time operation of operating systems and applications. The JVM memory layout defines the Java memory allocation, allocation, and management strategies during the running process, ensuring efficient and stable running of the JVM.There are some differences in how memory is divided and managed by different JVMS. Take a look at the classical JVM memory layout in conjunction with the JVM virtual machine specification.
  2. The data we get from disk or network IO needs to be loaded into memory first, and then the CPU gets the data from memory for readingCPUanddiskBridge between.

1.1.2 Thread memory space

  1. The Java virtual machine defines several run-time data areas that are used by programs during their execution: some of these are created when the virtual machine is started and destroyed when the virtual machine exits. Others are thread-specific, with thread-specific data areas created and destroyed as threads start and end.

  2. The gray ones are private to a single thread, and the red ones are shared by multiple threads. That is:

    • Thread-unique: includes independentlyProgram counter,The stack,Local method stack
    • Sharing between threads:The heap,Out of memory(Permanent generation or meta space, code cache)

1.1.3 Runtime class

There is only one Runtime instance per JVM. The runtime environment is equivalent to the box in the middle of the memory structure: runtime environment.

1.2 the thread

1.2.1 the JVM thread

  1. A thread is a unit of execution within a program. The JVM allows an application to have multiple threads running in parallel.

  2. In Hotspot JVM, each thread maps directly to the operating system’s native thread.

    • When a Java thread is ready to execute, an operating system native thread is created at the same time. When Java thread execution terminates, the local thread also recycles.
  3. The operating system is responsible for scheduling threads to any available CPU. Once the local thread initializes successfully, it calls the run() method in the Java thread.

1.2.2 JVM System Threads

  • If you usejconsoleOr any debugging tool, you can see a lot of threads running in the background. These background threads do not include callspublic static void main(String[])theThe main threadAnd all of thisThe main threadSelf – created thread.

The main backend threads in the Hotspot JVM are:

  • Virtual machine threads: This thread operation does not occur until the JVM reaches a safe point. The reason these operations must occur in different threads is that they all need the JVM to reach a safe point so that the heap does not change. The execution types of such threads include”stop-the-world“, thread stack collection, thread suspension, and bias lock revocation.
  • Periodic task threads: These threads are representations of periodic events (such as interrupts) and are typically used for scheduled execution of periodic operations.
  • GC thread: This thread provides support for different kinds of garbage collection behavior within the JVM.
  • Compile thread: This thread compiles bytecode to native code at run time.
  • Signal scheduling thread: This thread receives signals and sends them to the JVM for processing within it by calling the appropriate methods.

2. Program counter (PC register)

2.1 Introduction to PC registers

The official documentation site: docs.oracle.com/javase/spec…

  1. The program count register (Program Counter RegisterRegister is named after a CPU Register,Registers store instruction – related field information. The CPU can only run if it loads data into a register.
  2. Instead of referring to a physical register in a broad sense, it may be translated as a PC counter (orInstruction counter(also calledProgram hook), and it is not easy to cause some unnecessary misunderstanding.The PC register in the JVM is an abstract simulation of the physical PC register.
  3. It’s such a small amount of memory that you can barely remember it. It is also the fastest storage area.
  4. In the JVM specification, each thread has its own program counter, which is thread-private and whose lifetime is consistent with that of the thread.
  5. There is only one method executing on a thread at any one timeThe current method. The program counter stores the JVM instruction address of the Java method being executed by the current thread; Or, if it’s executingnativeMethod, is an unspecified value (undefned).
  6. It is an indicator of program control flow, and basic functions such as branching, looping, jumping, exception handling, thread recovery, and so on rely on this counter.
  7. The bytecode interpreter works by changing the value of this counter to select the next bytecode instruction to execute.
  8. It is aThe only oneThere are no provisions in the Java Virtual Machine specificationOutofMemoryErrorThe area of the situation.

2.2 Functions of the PC Register

The PC register is used to store the address pointing to the next instruction and the instruction code to be executed. The execution engine reads the next instruction and executes it.

For example, 2.3

public class PCRegisterTest {

    public static void main(String[] args) {
        int i = 10;
        int j = 20;
        int k = i + j;

        String s = "abc"; System.out.println(i); System.out.println(k); }}Copy the code

View bytecode

The method of the bytecode: blog.csdn.net/21aspnet/ar…

public class com.java.PCRegisterTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC.ACC_SUPER
Constant pool# 1:= Methodref          #6.#26         // java/lang/Object."<init>":()V
   #2 = String             #27            // abc
   #3 = Fieldref           #28.#29        // java/lang/System.out:Ljava/io/PrintStream;
   #4 = Methodref          #30.#31        // java/io/PrintStream.println:(I)V
   #5 = Class              #32            // com/atguigu/java/PCRegisterTest
   #6 = Class              #33            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/java/PCRegisterTest;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;) V #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               i
  #19 = Utf8               I
  #20 = Utf8               j
  #21 = Utf8               k
  #22 = Utf8               s
  #23 = Utf8               Ljava/lang/String;
  #24 = Utf8               SourceFile
  #25 = Utf8               PCRegisterTest.java
  #26 = NameAndType        #7: #8          // "<init>":()V
  #27 = Utf8               abc
  #28 = Class              #34            // java/lang/System
  #29 = NameAndType        #35: #36        // out:Ljava/io/PrintStream;
  #30 = Class              #37            // java/io/PrintStream
  #31 = NameAndType        #38: #39        // println:(I)V
  #32 = Utf8               com/java/PCRegisterTest
  #33 = Utf8               java/lang/Object
  #34 = Utf8               java/lang/System
  #35 = Utf8               out
  #36 = Utf8               Ljava/io/PrintStream;
  #37 = Utf8               java/io/PrintStream
  #38 = Utf8               println
  #39 = Utf8               (I)V
{
  public com.atguigu.java.PCRegisterTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/atguigu/java/PCRegisterTest;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;) Vflags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=5, args_size=1
         0: bipush        10
         2: istore_1
         3: bipush        20
         5: istore_2
         6: iload_1
         7: iload_2
         8: iadd
         9: istore_3
        10: ldc           #2                  // String abc
        12: astore        4
        14: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        17: iload_1
        18: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
        21: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        24: iload_3
        25: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
        28: return
      LineNumberTable:
        line 10: 0
        line 11: 3
        line 12: 6
        line 14: 10
        line 15: 14
        line 16: 21
        line 18: 28
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      29     0  args   [Ljava/lang/String;
            3      26     1     i   I
            6      23     2     j   I
           10      19     3     k   I
           14      15     4     s   Ljava/lang/String;
}
SourceFile: "PCRegisterTest.java"
Copy the code

2.4 Two interview questions

What is the use of using PC registers to store byte code instruction addresses? Or why use a PC register to record the execution address of the current thread?

  1. becauseCPUYou have to keep switching threads, and when you switch back, you have to know where to start.
  2. JVMThe bytecode interpreter needs to be changedPC registerTo specify what bytecode instruction should be executed next.

Why are PC registers private?

  • We all know that so-called multithreading only executes the methods of one thread at a particular time,CPUThere will be constant task switching, which will inevitably lead to frequent interruptions or recoveries, 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 do independent calculations, so that there is no interference with each other.
  • Due to theCPU time chip wheelLimit the number of threads executing concurrently. At any given moment, one processor or one core in a multi-core processor will execute only one instruction in a particular thread.
  • 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.

2.5 CPU Time slice

  1. CPU time slicenamelyCPUThe time allocated to each program. Each thread is allocated a time period, called its time slice.
  2. On a macro level: we can have multiple applications open at the same time, each running in parallel.
  3. But at the micro level: because there’s only oneCPUOne way to deal with fairness is to introduce time slices,Each program is executed in turn.

3. Local method interface

3.1 Local Methods

  1. In a nutshell,A Native Method is an interface for Java calls to non-Java codeaNative MethodIs a Java method whose implementation is implemented in a non-Java language, such as C. This feature is not unique to Java, many other programming languages have this mechanism, for example in C++, you can use itexternTell the C++ compiler to call a C function.

“A native method is A Java method whose implementation is provided by non-Java code.”

  1. The purpose of the native interface is to fuse different programming languages for Java, which was originally intendedFusion OF C/C++ programs.

For example:

One thing to note: identifiers`native`Can be used with other Java identifiers, however`abstract`With the exception ofCopy the code

public class IHaveNatives {
    public native void Native1(int x);

    public native static long Native2();

    private native synchronized float Native3(Object o);

    native void Native4(int[] ary) throws Exception;
    
}
Copy the code

3.2 Why use Native Method?

Java is very convenient to use, but problems arise when there are levels of tasks that are not easy to implement in Java, or when we are concerned about program efficiency.

3.2.1 Diplomacy with the Java Environment

Sometimes Java applications need to interact with hardware environments outside of Java, which is the main reason for the existence of native methods. You can think of a situation where Java needs to exchange information with some underlying system, such as an operating system or some hardware. The native method is just such a communication mechanism: it gives us a very concise interface, and we don’t have to learn the tedious details outside of Java applications.

3.2.2 Interaction with the operating system

  1. The JVM supports the Java language itself and runtime libraries, which are the platform on which Java programs live. It consists of an interpreter (interpreting bytecode) and libraries that connect to native code.
  2. However, it is not a complete system, and it often depends on the support of an underlying system. These underlying systems are often powerful operating systems.
  3. By using native methods, we were able to implement the INTERACTION of the JRE with the underlying system in Java, and even some parts of the JVM were written in C.
  4. Also, we need to use native methods if we want to use some features of the operating system that the Java language itself does not provide for encapsulation.

3.2.3 Sun’s Java

  1. Sun’s interpreter is implemented in C, which allows it to interact with the outside world just like normal C. The JRE is mostly implemented in Java, and it also interacts with the outside world through some native methods.
  2. For example, java.lang.ThreadsetPriority()Method is implemented in Java, but its implementation calls native methods in the classsetPriority0(). This native method is implemented in C and built into the JVM on the Windows 95 platform, and this native method will eventually be calledWin32 setpriority() API. This is a concrete implementation of a local method provided directly by the JVM, or more often by an external dynamically linked library (external dynamic link library), which is then called by the JVM.

3.2.4 Status of local methods

This approach is being used less and less today, except in hardware-related applications, such as driving printers through Java programs or managing production equipment through Java systems, 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.

4. Local method stack

  1. The Java virtual machine stack is used to manage calls to Java methods, while the local method stack is used to manage calls to local methods.

  2. The local method stack is also thread-private.

  3. Allows fixed or dynamically expandable memory size to be implemented (the same as the virtual stack in terms of memory overflow)

    • If thread requests allocate more stack capacity than the maximum allowed by the local method stack,The Java virtual machineOne will be thrownstackoverflowErrorThe exception.
    • If the local method stack can scale dynamically and there is not enough memory to allocate when trying to scale, or there is not enough memory to create the corresponding local method stack when a new thread is createdThe Java virtual machineOne will be thrownoutofMemoryErrorThe exception.
  4. Native methods are generally implemented in C or C++.

  5. It is implemented by registering Native methods in the Stack and loading the local Method library at Execution Engine time.

Matters needing attention

  1. 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
  2. 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.

  3. In Hotspot JVM, the local method stack and virtual machine stack are combined directly.

5. Reference and thanks

⭐ Song Hongkang is silicon valley – the JVM full tutorial a: www.bilibili.com/video/BV1PJ…

In Depth Java Virtual Machine Version 3