Java 程序运行原理分析

作者: 右耳菌 | 来源:发表于2022-05-25 08:55 被阅读0次

1. class 文件内容

class 文件包含JAVA程序执行的字节码;数据严格按照格式紧凑排列在class文件中的二进制流,中间无任何分隔符;文件开头有一个 0xcafebabe(16进制) 特殊的一个标志。

class文件16进制
class文件中包含了很多内容:
  • 版本
  • 访问标志
  • 常量池
  • 当前类
  • 超级类
  • 接口
  • 字段
  • 方法
  • 属性

2. JVM运行时数据区

JVM运行时数据区
  • 线程独占: 每个线程都会有它独立的空间,随线程生命周期而创建和销毁
  • 线程共享:所有线程能访问这块内存数据,随虚拟机或者GC而创建和销毁
2.1 方法区

JVM用来存储加载的类信息、常量、静态变量、编译后的代码等数据虚拟机规范中这是一个逻辑区划。具体实现根据不同虚拟机来实现。如: oracle的HotSpot在java7中方法区放在永久代,java8放在元数据空间,并且通过GC机制对这个区域进行管理

2.2 堆内存
堆内存
堆内存还可以细分为:老年代、新生代(Eden、From Survivor、To Survivor)JVM启动时创建,存放对象的实例。垃圾回收器主要就是管理堆内存。如果满了,就会出现OutOfMemoryError,更详细内容后续再延伸。
2.3 虚拟机栈

虚拟机栈,每个线程都在这个空间有一个私有的空间。线程栈由多个栈帧(Stack Frame)组成。一个线程会执行一个或多个方法,一个方法对应一个栈帧。栈帧内容包含:局部变量表、操作数栈、动态链接、方法返回地址、附加信息等。栈内存默认最大是1M,超出则抛出StackOverflowError.

2.4 本地方法栈

和虚拟机栈功能类似,虚拟机栈是为虚拟机执行JAVA方法而准备的,本地方法栈是为虚拟机使用Native本地方法而准备的。虚拟机规范没有规定具体的实现,由不同的虚拟机厂商去实现。HotSpot虚拟机中虚拟机栈和本地方法栈的实现是一样的。同样,超出大小以后也会抛出StackOverflowError.

2.5 程序计数器

程序计数器(Program Counter Register)记录当前线程执行字节码的位置,存储的是字节码指令地址,如果执行Native方法,则计数器值为空。每个线程都在这个空间有一个私有的空间,占用内存空间很少。CPU同一时间,只会执行一条线程中的指令。JVM多线程会轮流切换并分配CPU执行时间的方式。为了线程切换后,需要通过程序计数器,来恢复正确的执行位置。

3. 查看class文件内容

  • demo1.java
public class Demo1{
    public static void main(String[] args){
        int x = 500;
        int y = 100;
        int a = x / y;
        int b = 50;
        System.out.println(a + b);
    }
}
  • 编译文件
javac Demo1.java
  • javap 查看内容
javap -v Demo1.class > Demo1.txt
  • Demo1.txt
Classfile /G:/neteasy/subject-2/2.1-java程序运行原理/1.1.1-JAVA程序运行原理分析-资料包 - 副本/Demo1.class
  Last modified 2022年5月24日; size 414 bytes
  SHA-256 checksum 469b303454945dbe757e43d1f687116173c0d2fff5c37d461e6175b16194b45b
  Compiled from "Demo1.java"
public class Demo1
  minor version: 0
  major version: 57
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #19                         // Demo1
  super_class: #2                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Fieldref           #8.#9          // java/lang/System.out:Ljava/io/PrintStream;
   #8 = Class              #10            // java/lang/System
   #9 = NameAndType        #11:#12        // out:Ljava/io/PrintStream;
  #10 = Utf8               java/lang/System
  #11 = Utf8               out
  #12 = Utf8               Ljava/io/PrintStream;
  #13 = Methodref          #14.#15        // java/io/PrintStream.println:(I)V
  #14 = Class              #16            // java/io/PrintStream
  #15 = NameAndType        #17:#18        // println:(I)V
  #16 = Utf8               java/io/PrintStream
  #17 = Utf8               println
  #18 = Utf8               (I)V
  #19 = Class              #20            // Demo1
  #20 = Utf8               Demo1
  #21 = Utf8               Code
  #22 = Utf8               LineNumberTable
  #23 = Utf8               main
  #24 = Utf8               ([Ljava/lang/String;)V
  #25 = Utf8               SourceFile
  #26 = Utf8               Demo1.java
{
  public Demo1();
    descriptor: ()V
    flags: (0x0001) 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 1: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=5, args_size=1
         0: sipush        500
         3: istore_1
         4: bipush        100
         6: istore_2
         7: iload_1
         8: iload_2
         9: idiv
        10: istore_3
        11: bipush        50
        13: istore        4
        15: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        18: iload_3
        19: iload         4
        21: iadd
        22: invokevirtual #13                 // Method java/io/PrintStream.println:(I)V
        25: return
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 5: 7
        line 6: 11
        line 7: 15
        line 8: 25
}
SourceFile: "Demo1.java"

  • 版本号/访问控制
    版本号/访问控制
    版本号规则:JDK5,6,7,8分别对应49,50,51,52

访问标志

标志名称 标志值 含义
ACC_PUBLIC 0x0001 是否为public类型
ACC_FINAL 0x0010 是否被声明为final,只有类可设置
ACC_INTERFACE 0x0020 是否允许使用invokespecial字节码指令,JDK1.2之后编译出来的类的这个标志为true
ACC_INTERFACE 0x0200 标志这个是一个接口
ACC_ABSTRACT 0x0400 是否为abstract类型,对于接口或抽象类来说,此标志值为true,其他值为false
AcC_SYNTHETIC 0x1000 标志这个类并非由用户产生的
ACC_ANNOTATION 0x2000 标识这个一个注解
ACC_ENUM 0x4000 标识这个一个注解

  • 常量池 Constant pool
// 常量池
Constant pool:  
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Fieldref           #8.#9          // java/lang/System.out:Ljava/io/PrintStream;
   #8 = Class              #10            // java/lang/System
   #9 = NameAndType        #11:#12        // out:Ljava/io/PrintStream;
  #10 = Utf8               java/lang/System
  #11 = Utf8               out
  #12 = Utf8               Ljava/io/PrintStream;
  #13 = Methodref          #14.#15        // java/io/PrintStream.println:(I)V
  #14 = Class              #16            // java/io/PrintStream
  #15 = NameAndType        #17:#18        // println:(I)V
  #16 = Utf8               java/io/PrintStream
  #17 = Utf8               println
  #18 = Utf8               (I)V
  #19 = Class              #20            // Demo1
  #20 = Utf8               Demo1
  #21 = Utf8               Code
  #22 = Utf8               LineNumberTable
  #23 = Utf8               main
  #24 = Utf8               ([Ljava/lang/String;)V
  #25 = Utf8               SourceFile
  #26 = Utf8               Demo1.java

类信息包含的静态常量,编译之后就能确认

常量 含义
CONSTANT_utf8_info UTF-8编码的字符串
CONSTANT_Integer_info 整形字面量
CONSTANT_Float_info 浮点型字面量
CONSTANT_Long_info 长整型字面量
CONSTANT_Double_info 双精度浮点型字面量
CONSTANT_Class_info 类或接口的符号引用
CONSTANT_String_info 字符串类型字面量
CONSTANT_Fieldref_info 字段的符号引用
CONSTANT_Methodref_info 类中方法的符号引用
CONSTANT_InterfaceMethodref_info 接口中方法的符号引用
CONSTANT_NameAndType_info 字段或方法的符号引用
CONSTANT_MothodType_info 标志方法类型
CONSTANT_MethodHandle_info 表示方法句柄
CONSTANT_lnvokeDynamic_info 表示一个动态方法调用点
  • 构造方法
  public Demo1();
    descriptor: ()V
    flags: (0x0001) 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 1: 0

Demo1这个示例中,我们并没有写构造函数。由此可见,没有定义构造函数时,会有隐式的无参构造函数。

  • 程序入口main方法
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=5, args_size=1
         0: sipush        500
         3: istore_1
         4: bipush        100
         6: istore_2
         7: iload_1
         8: iload_2
         9: idiv
        10: istore_3
        11: bipush        50
        13: istore        4
        15: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
        18: iload_3
        19: iload         4
        21: iadd
        22: invokevirtual #13                 // Method java/io/PrintStream.println:(I)V
        25: return
解析参考

4. 程序完整运行分析:

程序完整运行分析一
程序完整运行分析二
i程序完整运行分析三
JVM指令码表 (多图预告,后续有空再更新为表格样式吧~~~~~,某云一上就容易被锁定)
image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

如果觉得有收获就点个赞吧,更多知识,请点击关注查看我的主页信息哦~

相关文章

  • Java程序运行原理分析

    一. JVM原理 class文件内容 JVM运行时数据区 线程独占: 每个线程都会有它独立的空间,随线程的生命周而...

  • java程序运行原理分析

    什么是class文件 是jvm编译java代码后生成的字节码文件,包含java程序执行的字节码;数据严格按照格式紧...

  • Java 程序运行原理分析

    1. class 文件内容 class 文件包含JAVA程序执行的字节码;数据严格按照格式紧凑排列在class文件...

  • JAVA程序运行原理分析(一)

    作为JAVA的开发人员,需要知道JAVA是如何运行的,这个需要好好思考下。 (一)class文件内容 class文...

  • JAVA程序运行原理

    JAVA程序运行原理 编写 .java 源文件 编译成 .class 文件 运行分配 JVM 数据区 JVM 运行...

  • JAVA开发:开发属于你的第一个Java程序

    01_开发属于你的第一个Java程序 Java程序的运行原理 Java程序追求的目标是一次编译到处运行,那他是如何...

  • 1.Java程序运行原理分析

    class文件内容class文件包含Java程序执行的字节码;数据严格按照格式紧凑排列在class文件中的二进制流...

  • 1.1.1 Java程序运行原理的分析

    首先需要了解JVM运行时数据区,里面分 线程共享区域:所有线程能访问这块内存数据,随虚拟机或GC而创建或销毁。方法...

  • Java程序运行原理

    编译生成.class字节码文件 class文件内容版本号访问控制标志常量池构造方法自定义方法指令(参照指令表) J...

  • Java程序运行原理

    java与jvm 一个语言为何这么写是由于它的语言规范决定的。而jvm规定了字节码如何运行的规范。而字节码的来源可...

网友评论

    本文标题:Java 程序运行原理分析

    本文链接:https://www.haomeiwen.com/subject/anheprtx.html