接上一篇 一个java程序是怎样运行起来的(2),在jvm创建好后,就可以开始执行程序了。我们知道,程序执行的入口在main函数,所以我们首先得找到main函数,这得有个前提,main函数对应的类已经被jvm加载了,所以jvm做的第一件事就是去加载类。先来看下java类加载的机制,主要有以下几个阶段:

1,加载:

加载阶段可以参考java.lang.ClassLoader中loadClass方法,采用的是双亲委托进制进行加载,这个阶段首先找到对应的class文件,以二级制方式读入内存,按照jvm规范解析出所表达的数据结构,在内存中生成一个代表该类的java.lang.Class对象.

2,验证:

验证是确保当前class文件格式符合jvm规范,不会对jvm产生危害。验证工作并不是在加载之后才开始的,比如从class文件读入到内存后,解析其代表的数据结构时,我们首先会去校验魔数是否正确,以及版本号是否符合要求等

3,准备

准备阶段主要是为类的静态变量分配内存,设定初始值等工作

4,解析

常量池中的符号引用替换为直接引用,比如String str = "test",str指向常量池中"test"的地址

5,初始化

这个过程主要是执行类构造器的方法,静态类的赋值,静态代码块的执行。如果初始化一个类时,发现父类还没有初始化,则需要先初始化父类

根据一个java程序是怎样运行起来的(1),类加载完成后,就可以找到main方法了,这时就可以开始执行main方法中的jvm指令了,下面以一个例子来解释其执行过程。

测试代码如下:

public class TestAdd{public static void main(String[] args){int a = 1;int b = 2;int c = a+b;print(c);}public static void print(int c){System.out.println(c);}
}

javac编译后,利用命令javap -c TestAdd,我们来看下在运行时究竟执行了哪些jvm指令

public class TestAdd {public TestAdd();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_11: istore_12: iconst_23: istore_24: iload_15: iload_26: iadd7: istore_38: iload_39: invokestatic  #2                  // Method print:(I)V12: returnpublic static void print(int);Code:0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;3: iload_04: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V7: return
}

构造函数先不看,直接看main方法。函数的执行是在栈帧中执行的,执行的时候由程序计数器记录当前执行到哪个位置。栈帧存放在stack中,只有stack顶的栈帧当前有效,里面存放了本地变量表,操作数栈,返回地址等,本地变量表的大小,以及从操作数栈的深度在编译时就已经确定,运行时不会改变,如下图:

他们之间的调用关系是栈帧1的函数调用了栈帧2中的函数,栈帧2中国的函数调用了栈帧3中的函数。有了这个基础,接下来看下上面的指令是如何执行的,入口在main方法,此时分配新的栈帧我把它标记为栈帧1,栈帧1处在stack顶,即为当前栈帧,执行main方法中jvm指令之前,栈帧1中的有关数据结构如下,本地变量表index为0变量存放的是函数的参数args:

执行指令iconst_1,将int类型数字1push到操作数栈,此时栈帧1的数据结构为:

执行指令istore_1,将栈帧1中操作数栈执行退栈操作,所得的值放入到本地变量表第1个变量中,此时栈帧1的数据结构:

iconst_2,istore_2与上面同理,执行后栈帧:

iload_1和iload_2分别把本地变量表中第一个和第二个变量的值压入到操作数栈,

iadd指令,连续两次操作数栈执行退栈操作,将所得的值相加得到结果3再次压入操作数栈

istore_3,将操作数栈栈顶元素退栈,所得的值存入第3个本地变量中

iload_3,将本地变量表中第三个变量的值压入操作数栈中

invokestaic 调用静态方法,此处存在方法调用,需要新开辟一个栈帧压入stack,并把变量值3入本地变量表,其返回地址为main方法中即将执行的指令return的地址,这个暂按照指令集的排列,标记为frame1_12吧,此时当前栈帧为栈帧2,运行时数据结构为:

接下来看下print方法的执行,

getstatic获取指定的field,

iload_0,将变量0的值3压入操作数栈,此时数据结构为:

invokevirtual执行打印方法,会新开辟一个栈帧栈帧3,将变量值3入栈帧3的本地变量表,其返回地址为frame2_7,执行return后,当前栈帧栈帧3退栈,栈帧2变成当前栈帧,发现当前执行的指令为return执行退栈操作,当前栈帧为栈帧1,此时栈帧1要执行的指令为return,退栈,至程序结束退出。

至此,把java程序的执行过程简单过了一遍,过程非常粗糙,我目前对jvm的了解有限,后续有更好更深入的理解后,再回过头来丰富下。

上面方法调用时的栈帧等数据结构可以参见本人编写的jvm尝试: https://github.com/reverence/czvm

一个java程序是怎样运行起来的(3)相关推荐

  1. 编译运行一个java程序_如何从另一个Java程序编译和运行Java程序

    编译运行一个java程序 Have you ever thought if it's possible to compile and run a java program from another j ...

  2. 一个Java程序是怎样运行起来的【class解析全过程】

    首先编写一测试程序 public class Test {public static void main(String[] args){System.out.println("HelloWo ...

  3. 3. 第一个 Java 程序 - Hello World【连载 3】

    在上一篇文章 [准备编译环境]中我们完成了 Java 编译环境的搭建,这篇文章内容主要是来教你怎么开始编写第一个 Java 程序,并运行它. 分为两个步骤,首先我会一步一步的告诉你如何编写一个简单的 ...

  4. 如何把一个java程序打包成exe文件,运行在没有java虚

    如何把一个java程序打包成exe文件,运行在没有java虚 核心提示:首先,将编译好的程序打包成jar文件,然后做出exe,这样代码就不可见了:但是exe文件在没有安装jre的电脑上不能运行,如果要 ...

  5. 新建一个java程序并运行

    新建一个java程序并运行 使用MyEclipse新建一个程序 新建一个class文件 项目名,右击 弹出的菜单中,填写类名称 文件创建成功 关注 有了一个Demon.java文件 代码中自动有了内容 ...

  6. 一个java程序_从另一个java程序运行java程序

    我正在研究一个简单的java程序.它只是编译并执行另一个java程序.我正在使用Runtime.exec()函数进行编译和运行.编译没有问题.但是当它运行时,如果第二个程序需要输入来从键盘读取,我不能 ...

  7. cmd 将文件夹下文件剪切到另外一个文件_手把手教你运行第一个 Java 程序,看不懂你来骂我!...

    码字不易,对你有帮助 **点赞 /转发↪️/关注 ** 支持一下作者 微信搜公众号:不会编程的程序圆br/>看更多干货,获取第一时间更新 在运行第一个 java 程序之前,你需要先将 java ...

  8. 一步控制台编译java_在控制台运行一个 Java 程序 Test . class ,使用的命令正确的是( )_学小易找答案...

    [多选题]城市轨道交通自动售检票系统架构包括 [填空题]区域式架构是在( )和( )基础上设置的一个路网中心 [填空题]在危险.安全.喜庆.阴霾等不同气氛下的场景色彩基调是__________. [单 ...

  9. 强哥带你零基础学java-03运行第一个java程序

    java是什么,java是一种编程语言的名字,在生活中,我们知道的有汉语,英语.运用汉语语法,我们可以写一篇文章.同样的道理,用java的语法,我们就可以写程序了. 那么现在的问题是,要如何来写呢?现 ...

最新文章

  1. python 发送邮件connect none_使用python向IP地址发送邮件
  2. 数据库安全性概念与自主安全性机制
  3. UFT QTP 12 试用
  4. 语法分析器的生成器——Bison
  5. 小波分解和小波包分解
  6. Android ndk下载和环境配置
  7. 在线预览CAD 在线预览office 在线预览3D模型
  8. Mac词典扩充、本地化
  9. echarts 柱状图颜色及渐变色设置
  10. win7无法搜索到网络计算机,笔记本win7系统搜索不到无线网络信号怎么解决
  11. C7:如何使用JEPG Simulation进行ColorTuning?
  12. 动态规划求解机器人有多少种可能的路径
  13. 病案首页计算机管理系统功能一般不包括,病案管理系统
  14. 我的一次创业经历--分享给希望创业的大学生们 .
  15. 项目经理需要的基本技能
  16. Java log日志
  17. php集成环境和自己配置的区别,php集成环境、php绿色集成环境、php独立安装版环境这三者的区别
  18. git(9)Git 内部原理,java入门视频百度网盘
  19. Spring调用Feign报错:java.io.IOException: Incomplete output stream
  20. 元宇宙区块链游戏开发 元宇宙手机游戏开发

热门文章

  1. SpringBoot + Flyway 发版再也不怕忘执行 SQL了
  2. C++ 实现 力扣1039. 多边形三角剖分的最低得分
  3. 心电信号matlab处理,基于MATLAB的心电信号的数字滤波处理
  4. CRC-16/XMODEM串行计算的Verilog源码及仿真
  5. 【前端学习之路】——使用jQuery制作放大镜
  6. 王者荣耀中的数学原理及游戏策略(一)防御篇(护甲|魔抗|伤害运算机制)
  7. CentOS 8通过DNF命令安装最新版的LNMP(Linux+Nginx+MariaDB+PHP)
  8. 〖Python 数据库开发实战 - Redis篇②〗- Linux系统下安装 Redis 数据库
  9. 如何恢复手机通话记录?教你快速恢复
  10. 4个方法调动员工的OKR积极性