欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JVM字节码技术

程序员文章站 2022-04-18 16:43:12
...

JVM字节码技术

不积细流无以成江河

1.什么是字节码为什么要学习字节码

Java 字节码:

bytecode,是Java代码编译后的中间代码格式。JVM需要读取并解析字节码才能执行相应的任务。JVM字节码是JVM的指令集。JVM加载字节码格式的class文 件,校验之后通过编译器转换为本地机器代码执行。

java bytecode 由单个字节组成(所以java的操作码又叫做字节码),所以最多有256个操作吗。实际上Java只使用了200左右的操作码, 还有一些操作码则保留给调试操作。

分类(指令性质):

  • 程序流程控制指令
  • 算术运算指令以及类型转换指令
  • 对象操作指令
  • 栈操作指令 (包括局部变量交互指令)

学习字节码的好处?

1.了解字节码及其工作原理,对于编写高性能代码至关重要。

2.对于深入分析和排查问题也有一定作用,所以我们要想深入了解JVM来说,了解

字节码也是夯实基础的一项基本功

3.同时对于我们开发人员来时,不了解平台的底层原理和实现细节,想要职业进阶绝对不是长久之计,毕竟我们都希望成为更好的程序

员,。


2.获取字节码齐清单

java代码:

public class HelloByteCode {
    public static void main(String[] args) {
        HelloByteCode helloByteCode = new HelloByteCode();
    }
}
2.1编译反编译(助记符)
javac HelloByteCode.java
javap -c HelloByteCode
警告: 二进制文件HelloByteCode包含com.zhang.demo.HelloByteCode
Compiled from "HelloByteCode.java"
public class com.zhang.demo.HelloByteCode {
	//上边为反编译之后的类, 原类里边只有一个方法 编译反编译后 就出现了两个方法,我们都知道再某些情况下 会自动  生成构造方法,这里验证了构造方法是在编译期间自动生成的 。
  public com.zhang.demo.HelloByteCode();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/zhang/demo/HelloByteCode
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: return
}

2.2 查看常量池信息

常量池 大家应该都听说过, 英文是 Constant pool 。这里做一个强调: 大多数时候 指的是 运行时常量池 。但运行时常量池里面的常量是从哪里来的呢? 主要就是由 class 文件中的 常量池结构体 组成的。

javap -c -verbose HelloByteCode

警告: 二进制文件HelloByteCode包含com.zhang.demo.HelloByteCode
Classfile /Users/zy1994/Desktop/zhangyang/AAAA-jk/jvm/code/demo/src/main/java/com/zhang/demo/HelloByteCode.class
  Last modified 2020-10-30; size 303 bytes
  MD5 checksum 2a667aec3dbde61f2a4ffd2412d0acd8
  Compiled from "HelloByteCode.java"
public class com.zhang.demo.HelloByteCode
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#13         // java/lang/Object."<init>":()V
   #2 = Class              #14            // com/zhang/demo/HelloByteCode
   #3 = Methodref          #2.#13         // com/zhang/demo/HelloByteCode."<init>":()V
   #4 = Class              #15            // java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Utf8               LineNumberTable
   #9 = Utf8               main
  #10 = Utf8               ([Ljava/lang/String;)V
  #11 = Utf8               SourceFile
  #12 = Utf8               HelloByteCode.java
  #13 = NameAndType        #5:#6          // "<init>":()V
  #14 = Utf8               com/zhang/demo/HelloByteCode
  #15 = Utf8               java/lang/Object

SourceFile: "HelloByteCode.java"

major version: 52 (jdk的版本是从45开始的 所以当前的jdk版本是8)

flags: ACC_PUBLIC, ACC_SUPER

ACC_PUBLIC 说明该类是一个PUBLIC的类 ,ACC_SUPER 仅仅是jdk的历史遗留问题需要一直加上的。

我们可以看到常量池中有大量的#号,这就是通常所说的符号引用,因为在类加载之前jvm是不知道这些类方法的具体地址的,所以就需要用一个符号引用先进性代替,再链接的解析阶段这些符号引用才会转化成具体的引用。

那下边的这天语句来进行解析一下常量池:

#1 = Methodref #4.#13 // java/lang/Object.""????)V

  • Methodref 当前符号引用(常量引用)指向的是一个方法。
  • 记下来可以看到是调用一个类的方法 根据常量表查找可以看到是Object类的init方法 当然后边的注释也进行了解读,方法的返回值 V 就是没有返回值的意思。
2.3 查看方法信息

栈帧(Frame)模型 java的线程栈是由多个栈帧组成的,每一次方法调用都会生成一个栈帧 压入栈中

下图为栈帧的构成:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U8P4myR5-1604280603056)(/Users/zy1994/Library/Application Support/typora-user-images/image-20201030165131966.png)]

栈帧主要有三个部分构成:

  • 局部变量数组
    • 存储的是局部变量的值或者引用 包含了方法的参数和局部变量的参数 (编译时确定)
  • 操作数栈
    • FILO的数据结构主要是执行jvm的操作指令
  • class引用

编译和反编译

javac -g xxx
javap -c -verbose xxx

创建对象指令

public com.zhang.demo.HelloByteCode();
    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 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/zhang/demo/HelloByteCode;

相关标签: java jvm