Java bytecode is an instruction format that the JVM executes, using bytecode instructions to perform corresponding actions

Bytecode viewing (mnemonic -> binary)

The.class file itself is a binary file, and we can view it in two ways. One is to view its binary contents directly, which is not easy to view and understand, and the other is to see its contents in mnemonic mode through Javap, which is easy to understand

Binary viewing mode

Binary viewer

Since binary files in computers are usually escaped by text editors when opened, it is recommended to use software such as Winhex for easy understanding

Mnemonic view

javap

You can use the javac command to compile.java files into.class files, which are called Java bytecode files.

You can run the javap -c command to view the bytecode of the. Class file.

You can run the javap -c -verbose command to view detailed information about bytecode.

The IDEA of the plugin

The Jclasslib Bytecode Viewer plug-in makes it easy to view the compiled Bytecode files of each Java class

Simple bytecode parsing

Java code before compilation

package com.rrtx.adm;

/** * Created by yarne on 2021/7/3. */
public class Main {
    public static void main(String[] args) {
        int a = 5;
        double b = 2.00;
        String c = "3";
        add(c,a,b);
    }
    public static void add(String a,int b,double c){
        doublev = Integer.valueOf(a) + b + c; System.out.println(v); }}Copy the code

View bytecode (mnemonic) for.class

Classfile /C:/Users/14641/Desktop/Main.class
  Last modified 2021-7-4; size 890 bytes
  MD5 checksum 683b4cdcd60108ce5bfdcc9e6fe3c992
  Compiled from "Main.java"
public class com.rrtx.adm.Main
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC.ACC_SUPER
Constant pool# 1:= Methodref          #11.#34        // java/lang/Object."<init>":()V
   #2 = Double             2.0 d
   #4 = String             #35            / / 3
   #5 = Methodref          #10.#36        // com/rrtx/adm/Main.add:(Ljava/lang/String; ID)V
   #6 = Methodref          #37.#38        // java/lang/Integer.valueOf:(Ljava/lang/String;) Ljava/lang/Integer;
   #7 = Methodref          #37.#39        // java/lang/Integer.intValue:()I
   #8 = Fieldref           #40.#41        // java/lang/System.out:Ljava/io/PrintStream;
   #9 = Methodref          #42.#43        // java/io/PrintStream.println:(D)V
  #10 = Class              #44            // com/rrtx/adm/Main
  #11 = Class              #45            // java/lang/Object
  #12 = Utf8               <init>
  #13 = Utf8               ()V
  #14 = Utf8               Code
  #15 = Utf8               LineNumberTable
  #16 = Utf8               LocalVariableTable
  #17 = Utf8               this
  #18 = Utf8               Lcom/rrtx/adm/Main;
  #19 = Utf8               main
  #20 = Utf8               ([Ljava/lang/String;)V
  #21 = Utf8               args
  #22 = Utf8               [Ljava/lang/String;
  #23 = Utf8               a
  #24 = Utf8               I
  #25 = Utf8               b
  #26 = Utf8               D
  #27 = Utf8               c
  #28 = Utf8               Ljava/lang/String;
  #29 = Utf8               add
  #30= Utf8 (Ljava/lang/String; ID)V #31 = Utf8               v
  #32 = Utf8               SourceFile
  #33 = Utf8               Main.java
  #34 = NameAndType        #12: #13        // "<init>":()V
  #35 = Utf8               3
  #36 = NameAndType        #29: #30        // add:(Ljava/lang/String; ID)V
  #37 = Class              #46            // java/lang/Integer
  #38 = NameAndType        #47: #48        // valueOf:(Ljava/lang/String;) Ljava/lang/Integer;
  #39 = NameAndType        #49: #50        // intValue:()I
  #40 = Class              #51            // java/lang/System
  #41 = NameAndType        #52: #53        // out:Ljava/io/PrintStream;
  #42 = Class              #54            // java/io/PrintStream
  #43 = NameAndType        #55: #56        // println:(D)V
  #44 = Utf8               com/rrtx/adm/Main
  #45 = Utf8               java/lang/Object
  #46 = Utf8               java/lang/Integer
  #47 = Utf8               valueOf
  #48= Utf8 (Ljava/lang/String;) Ljava/lang/Integer; #49 = Utf8               intValue
  #50 = Utf8               ()I
  #51 = Utf8               java/lang/System
  #52 = Utf8               out
  #53 = Utf8               Ljava/io/PrintStream;
  #54 = Utf8               java/io/PrintStream
  #55 = Utf8               println
  #56 = Utf8               (D)V
{
  public com.rrtx.adm.Main();
    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 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/rrtx/adm/Main;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=5, args_size=1
         0: iconst_5
         1: istore_1
         2: ldc2_w        #2                  / / double 2.0 d
         5: dstore_2
         6: ldc           #4                  // String 3
         8: astore        4
        10: aload         4
        12: iload_1
        13: dload_2
        14: invokestatic  #5                  // Method add:(Ljava/lang/String; ID)V
        17: return
      LineNumberTable:
        line 8: 0
        line 9: 2
        line 10: 6
        line 11: 10
        line 12: 17
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      18     0  args   [Ljava/lang/String;
            2      16     1     a   I
            6      12     2     b   D
           10       8     4     c   Ljava/lang/String;

  public static void add(java.lang.String, int.double); descriptor: (Ljava/lang/String; ID)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=6, args_size=3
         0: aload_0
         1: invokestatic  #6                  // Method java/lang/Integer.valueOf:(Ljava/lang/String;) Ljava/lang/Integer;
         4: invokevirtual #7                  // Method java/lang/Integer.intValue:()I
         7: iload_1
         8: iadd
         9: i2d
        10: dload_2
        11: dadd
        12: dstore        4
        14: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        17: dload         4
        19: invokevirtual #9                  // Method java/io/PrintStream.println:(D)V
        22: return
      LineNumberTable:
        line 16: 0
        line 17: 14
        line 18: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      23     0     a   Ljava/lang/String;
            0      23     1     b   I
            0      23     2     c   D
           14       9     4     v   D
}
Copy the code

Structure that

By simply classifying the above bytecode files, you can divide a class into class summaries, constant pools, and method stack frames

The class the

The summary records some basic information about the class, including the size change time, checksum, JDK version information at compile time, and the scope of the class

Classfile /C:/Users/yarne/Desktop/Main.class    // From the desktop main. class file
  Last modified 2021-7-4; size 890 bytes        // Finally modify the time and class size
  MD5 checksum 683b4cdcd60108ce5bfdcc9e6fe3c992 / / the checksum
  Compiled from "Main.java"
public class com.rrtx.adm.Main
  minor version: 0 / /jdkThe child version numbermajor version: 52 / /jdkMajor version 52 means yesjava8
  flags: ACC_PUBLIC.ACC_SUPER                 //publicClass, the initialization method uses the parent classCopy the code

Flags Indicates the meaning of the identifier

Identifier name The identifier value paraphrase
ACC_PUBLIC 0x0001 Public type
ACC_FINAL 0x0010 The Final type
ACC_SUPER 0x0020 Whether the new semantics of the Invokespecial bytecode instruction are allowed
ACC_INTERFACE 0x0200 Interface modifier
ACC_ABSTRACT 0x0400 The abstract modifier
ACC_SYNTHETIC 0x1000 Indicates that this class is not generated by user code
ACC_ANNOTATION 0x2000 Annotation modifier
**ACC_ENUM 0x400 Enumeration modifier

Constant pool

A constant pool contains all of the primitive type constants ina class and symbolic references. Primitive constants include string constants, final-modified member variables, instance variables, etc. Symbolic references include class and interface names, field names and descriptions, and method names and descriptions

Primitive type constant

Constants of basic type include literals and referrals. Literals include text strings, final variables, and data values. For constants of basic value int, the pool value holds the reference and literal name, but does not hold the value of the data

#2 = Double             2.0 d		   // Double stores the actual value
#4 = String             #35            / / reference # 35
#35 = Utf8               3             // new String("3")
#23 = Utf8               a            //int stores only the name, not the actual value
#24 = Utf8               I
Copy the code

Symbolic reference

Symbolic references contain the names and descriptions of many classes, interfaces, fields, methods, and so on

   #5 = Methodref          #10.#36        // com/rrtx/adm/Main.add:(Ljava/lang/String; ID)V
   #6 = Methodref          #37.#38        // java/lang/Integer.valueOf:(Ljava/lang/String;) Ljava/lang/Integer;
   #7 = Methodref          #37.#39        // java/lang/Integer.intValue:()I
   #8 = Fieldref           #40.#41        // java/lang/System.out:Ljava/io/PrintStream;
   #9 = Methodref          #42.#43        // java/io/PrintStream.println:(D)V
  #10 = Class              #44            // com/rrtx/adm/Main
  #11 = Class              #45            // java/lang/Object
Copy the code

Methods the stack frame

Method stack frames are the methods in the class. Each method is a frame that is defined when the class is compiled, created from the definition when the thread is running, and destroyed when the call ends.

The JVM creates a stack frame for each method called in the current thread. The JVM creates a stack frame for each method called in the current thread. Each stack frame contains the local variable table, operation stack, dynamic link, return address, and some additional summary information. The stack frame is destroyed after being called

Here are all stack frames in main. class. There are two methods.

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=5, args_size=1
         0: iconst_5
         1: istore_1
         2: ldc2_w        #2                  / / double 2.0 d
         5: dstore_2
         6: ldc           #4                  // String 3
         8: astore        4
        10: aload         4
        12: iload_1
        13: dload_2
        14: invokestatic  #5                  // Method add:(Ljava/lang/String; ID)V
        17: return
      LineNumberTable:
        line 8: 0
        line 9: 2
        line 10: 6
        line 11: 10
        line 12: 17
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      18     0  args   [Ljava/lang/String;
            2      16     1     a   I
            6      12     2     b   D
           10       8     4     c   Ljava/lang/String;

  public static void add(java.lang.String, int.double); descriptor: (Ljava/lang/String; ID)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=6, args_size=3
         0: aload_0
         1: invokestatic  #6                  // Method java/lang/Integer.valueOf:(Ljava/lang/String;) Ljava/lang/Integer;
         4: invokevirtual #7                  // Method java/lang/Integer.intValue:()I
         7: iload_1
         8: iadd
         9: i2d
        10: dload_2
        11: dadd
        12: dstore        4
        14: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        17: dload         4
        19: invokevirtual #9                  // Method java/io/PrintStream.println:(D)V
        22: return
      LineNumberTable:
        line 16: 0
        line 17: 14
        line 18: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      23     0     a   Ljava/lang/String;
            0      23     1     b   I
            0      23     2     c   D
           14       9     4     v   D
}
Copy the code

The stack frame in this paper,

From the stack frame summary information, you can basically know the basic information about a method

 / / the main method
public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC       Static, public methods
    Code:
      stack=4, locals=5, args_size=1    // The stack frame depth is 4, the maximum local variables are 5, and the number of inputs is 1
                  

/ / the add method
 public static void add(java.lang.String, int.double); descriptor: (Ljava/lang/String; ID)V flags: ACC_PUBLIC, ACC_STATICStatic, public methods
    Code:
      stack=4, locals=6, args_size=3     // The stack frame depth is 4, the maximum local variables are 6, and the number of inputs is 3
Copy the code

Local variable scale

The local variable table is an array used to store local variables of the current method. The types that can be stored in the table include Boolean, byte, CHAR, short, int, float, and reference types. Since local variables are thread private, there is no problem with thread safety. This is done after the.class bytecode file is compiled

// the main method is a local variable table
LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      18     0  args   [Ljava/lang/String;  // Enter args as an array of type String
            2      16     1     a   I                 // local variable a of type I int
            6      12     2     b   D                 // local variable b of type D double
           10       8     4     c   Ljava/lang/String; // local variable c of type String

 // add method local variable table
LocalVariableTable:
        Start  Length  Slot  Name   Signature           
            0      23     0     a   Ljava/lang/String;   // enter parameter A, which is of type String
            0      23     1     b   I					// enter parameter b of type I
            0      23     2     c   D					// enter parameter c, type D
           14       9     4     v   D				    // Calculate the value v of type D
Copy the code

The operand stack

The operand stack is also a stack used for calculation. The method execution starts at the empty stack, proceeds to the stack according to the bytecode instructions, and then exits the stack. The stack size is also calculated after the class is compiled. The following is a brief look at the main method operand stack instruction execution flow

// Operand stack of main method
   		 0: iconst_5
         1: istore_1
         2: ldc2_w        #2                  / / double 2.0 d
         5: dstore_2
         6: ldc           #4                  // String 3
         8: astore        4
        10: aload         4
        12: iload_1
        13: dload_2
        14: invokestatic  #5                  // Method add:(Ljava/lang/String; ID)V
        17: return
Copy the code
Classification of instructions

According to the nature of instructions, they can be divided into four types:

  1. Stack manipulation instructions, including instructions to interact with local variables
  2. Program flow control instructions
  3. Object manipulation instructions, including method invocation instructions
  4. Arithmetic operations and type conversion instructions
Key instructions load&store

During a JVM run, all operations are performed on the virtual machine stack, but because the lifecycle of the stack is consistent with that of the thread, the stack is destroyed after each calculation, leaving no data. Therefore, during each stack operation, there will be a key action, which is to load data from the local variable table first, and then store it back after calculation

Common instruction types (just a few above)
  1. Load and store instructions load and store
  2. Constants define const
  3. LDC complex type definition
  4. Basic types :iconst, istore, iload I, which means int, and so on
I stands for int, L for long, S for short, B for byte, C for char, F for float, D for double, and a, unlike the others, is a reference typeCopy the code
  1. Invokestatic invokes static methods

  2. The stack return

Operation process
0: define a constant of type int as 5 1: store the constant of type int off the stack into an array of constants in slot 1 2: define type double 2.0 using the complex type referenced in #2 5: Insert a constant of type double into an array of constants in slot 2. 6: Define a String of type 3 using the complex type referenced in #4. 10: insert slot 4 into the constants array 12: insert slot 1 into the constants array 13: insert slot 2 into the constants array double 15: call the frame reference symbol #5 17: unstackCopy the code

conclusion

The above briefly introduced the way to view bytecode, the structure of bytecode files, and how to understand the bytecode runtime structure. As mentioned above, JVM is based on stack calculation, so understanding the stack and runtime structure can help me to have a deeper understanding of the actions of JVM stack runtime.

Finally, a cumbersome sentence is used to describe the call process between the thread stack and stack frame

Thread creation -> Thread stack Creation -> Call Stack FRAME A-> Call Stack Frame A-> Call stack Frame A-> Call stack Frame B-> Call stack Frame B-> Call stack Frame B-> Return stack Frame B-> Return stack Frame A-> Destroy stack Frame A-> Destroy thread stack -> Destroy thread

Reference:

www.lagou.com/lgeduarticl…

Segmentfault.com/a/119000003…

Infringement to delete