2025年一文搞懂 java -jar 发生了什么

一文搞懂 java -jar 发生了什么之前一直就很好奇 java jar 到底发生了什么 为什么执行 java jar 代码就自动运行了 今天我们来说明一下 尽量覆盖操作系统 编译原理 JVM 的一些东西 本文将处于一个不断更新的状态 知道上面这些东西覆盖的差不多了为止 如果可以的话 也会加上硬件方面的东西 主要的目的就是为了能以最简单的

大家好,我是讯享网,很高兴认识大家。

之前一直就很好奇 java -jar 到底发生了什么,为什么执行 java -jar 代码就自动运行了。今天我们来说明一下,尽量覆盖操作系统、编译原理、JVM 的一些东西。( 本文将处于一个不断更新的状态,知道上面这些东西覆盖的差不多了为止,如果可以的话,也会加上硬件方面的东西 ),主要的目的就是为了能以最简单的 java 代码来串一些相对来说比较底层的东西,让自己以及让每个读者对计算机能有一个相对全局的了解。

我们先约定如下:
1.操作系统仅仅指的是unix 或类unix
2. 64 位机器
3. 64位 jDK
我们把下面这个类,打成一个 jar 包然后执行。

 / * Created by shengjk1 on 2020/8/30. */ public class Test { 
    public static int b; private int a; public static void main(String[] args) { 
    Test test = new Test(); test.test(); System.out.println("b = " + b); System.out.println("执行完毕"); } public void test() { 
    byte i = 15; int j = 8; int k = i + j; } } 

讯享网

学过 java 的同学应该都知道这个 Test 类的每行代码都是干嘛的,就不一一解释了。

关于编译

首先会编译成 class 文件
在这里插入图片描述
讯享网关于 java 的编译器
在这里插入图片描述编译的 class 内容
在这里插入图片描述有 cafe babe 魔数,还有什么常量池呀之类的,稍后补充

下面开始执行

关于 shell

在这里插入图片描述
执行的时候我们启动了一个 命令行客户端 进程,可以理解为 shell 的一种。所谓的 shell 在操作系统中的位置
在这里插入图片描述
当然此 shell 非彼 shell,操作系统中的 shell 更加宽泛一下,像图形界面也是 shell 的一种。

关于进程

我们刚才仅仅用鼠标那么轻轻的一点就创建了一个 命令行客户端 进程,而对于操作系统而言进程是如何创建的呢?
会由用户态进入到内核态,然后由操作系统执行 fork 命令,此时进程开始创建,
会包括 虚拟地址空间、修改进程表、会占用寄存器、会有打开文件的清单等等信息,创建完成之后就可以执行了。我们的 命令行客户端 也就起来了
在这里插入图片描述等待用户输入,用户的每次输入,然后回车,其实对于操作系统而言都是创建一个新的进程。

执行 java -jar

在这里插入图片描述同理会 fork 一个 JVM 进程出来,JVM 创建的过程中会启动 Bootstrap ClassLoader 加载 Java 的核心类库 ( JAVA_HOME/jre/lib/rt.jar、resource.jar 或者是 sun.boot.class.path 路径下的内容 ),供 JVM 自身需要。( 关于 JDK、JRE、JVM 可以参考 读 Differences between JDK, JRE and JVM)

JVM 的准备工作完成之后,JVM会调用我们的 main() 方法,可是内存里面并没有 main 方法,这就是所说的 页面故障,操作系统会从磁盘上读取相应的指令。也就进入了 JVM 的类加载。

类加载

类加载得有加载器
在这里插入图片描述

加载

在这里插入图片描述

所以说未压缩的情况下 class 对象至少占用 8 byte( 32 位 JVM ) 16byte ( 64 位 JVM )

这个过程中,会把类的版本、字段、方法、等描述信息以及代码缓存放入 Metaspace,把常量池表中的各种字面常量符号引用等放入方法区的运行时常量池。
在这里插入图片描述

验证

同时会对 class 文件进行验证,包括文件格式、元数据等,以保证 class 文件不危害虚拟机自身的安全。

准备

加载验证结束后,开始进入准备阶段,主要做两件事情

  1. 类变量初始化,此处是初始化为 0 值,比如 int、long
  2. 初始化虚方法表 ( java 多态 ,也就是在运行期间才能确定具体调用哪个方法都可以称为虚方法 )

解析

准备阶段完成之后,开始解析,主要做一件事

  1. 将常量池中的符号引用转化为直接引用
    主要针对类或接口、字段、类方法、接口方法等

初始化

  1. 遇到 new、getstatic、putstatic或 invokestatic 时,如果未初始化则先初始化( 1. new 2.读取或设置一个类的静态字段 (被 final 修饰、已经在编译期把结果放入常量池的静态字段除外) 3. 调用一个类的静态方法 )
  2. 使用 java.lang.reflect 包的方法对类进行反射调用时,如果未初始化则先初始化
  3. 当初始化类时,如果其父类未初始化则先触发其父类初始化
  4. 当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先初始化这个类
  5. 当使用 动态语言支持时,如果 java.lang.invoke.MethodHandle 的解析结构为 REF_static、REF_new句柄,并且这个句柄对应类没有进行初始化,需要先初始化
  6. 当有 默认方法 接口的实现类发生了初始化,则该接口要在其初始化之前初始化
    接口并不要求父接口全都完成初始化,只有在真正使用到 父接口 的时候才会初始化
    类初始化其实就是调用类构造器() 方法的过程,而() 是由编译器 Javac 自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并而成的( 顺序不变 ),并且 JVM 会保证在子类 () 执行前,父类的()已经被执行完毕 ( 第一个被执行的 一定是 java.lang.Object ),并且 JVM 会保证一个类的 () 线程安全,被正确的加锁同步,并且有且仅会有一个线程去执行 () ( 同一个类加载器下,一个类型只会被加载一次 ),其他线程会阻塞直到 () 执行完毕

当然了类初始化完了之后如果需要会进行对象的初始化,调用对象的构造器 () ,调用之前会先调用父类的。

main 方法调用

执行 main 方法也就需要方法调用,对于方法调用 JVM 是通过几条指令来实现的
在这里插入图片描述方法对应的符号引用主要有两种

  1. 一部分在 类加载解析阶段或者第一次使用转为直接引用 ( 静态解析 方法在真正运行前就有一个可确定的调用版本,并且在运行期是不变的 。主要有静态方法和私有方法 ( 不可能通过继承或别的方式重写 ))
  2. 一部分在 每一次运行期间都转化为直接引用 ( 动态链接 invokevirtual )

main 方法执行

我们都知道方法是在栈中执行的,方法的执行过程其实就是不断的出栈入栈的过程
在这里插入图片描述在这里插入图片描述我们以 test() 方法为例来具体分析一下
在这里插入图片描述0: bipush 将 15 放入栈中
2: istore_1 将栈顶元素方入局部变量表第 1 个位置
3: bipush 将 8 放入栈中
5: istore_2 将栈顶元素方入局部变量表第 2 个位置
6: iload_1 将局部变量表的第 1 个位置元素放入栈
7: iload_2 将局部变量表的第 2 个位置元素放入栈
8: iadd 相加
9: istore_3 将栈顶元素(也就是相加的结果)方入局部变量表第 3 个位置
在这里插入图片描述===================================================

在这里插入图片描述===================================================
在这里插入图片描述===================================================
在这里插入图片描述===================================================

6,7 一起
在这里插入图片描述===================================================
在这里插入图片描述===================================================

在这里插入图片描述

然后 return ,主方法( 调用该方法的方法 )的 PC寄存器的值可以作为返回地址,然后继续执行。

打印输出

打印输出会从用户态进入内核态,操作系统会调用 IO 操作输出相应的结果。

退出

发生系统调用,JVM 退出

补充

  1. 在电脑中,系统调用(英语:system call),指运行在用户空间的程序向操作系统内核请求需要更高权限运行的服务。系统调用提供用户程序与操作系统之间的接口。大多数系统交互式操作需求在内核态运行。如设备IO操作或者进程间通信。

在这里插入图片描述2. 操作系统的进程空间可分为用户空间和内核空间,它们需要不同的执行权限。其中系统调用运行在内核空间。

3.常见系统调用
在这里插入图片描述

小讯
上一篇 2025-03-24 09:15
下一篇 2025-04-10 19:21

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/66296.html