Java 代码有很多种不同的运行方式。比如说可以在开发工具中运行,可以双击执行 jar 文件运行,也可以在命令行中运行,甚至可以在网页中运行。当然,这些执行方式都离不开 JRE,也就是 Java 运行时环境。
实际上,JRE 仅包含运行 Java 程序的必需组件,包括 Java 虚拟机以及 Java 核心类库等。我们 Java 程序员经常接触到的 JDK(Java 开发工具包)同样包含了 JRE,并且还附带了一系列开发、诊断工具。
然而,运行 C++ 代码则无需额外的运行时。我们往往把这些代码直接编译成 CPU 所能理解的代码格式,也就是机器码。(运行时系统是一种介乎编译(Compile)和解释(Interpret)的运行方式,由编译器(Compiler)首先将源代码编译为一种中间码,在执行时由运行时(Runtime)充当解释器(Interpreter)对其解释。该过程以运行时为先决条件,因此系统被称为运行时系统。Java 的运行时被称为Java运行环境(Java Runtime Environment, JRE)
为什么 Java 要在虚拟机里运行?Java 作为一门高级程序语言,它的语法非常复杂,抽象程度也很高。因此,直接在硬件上运行这种复杂的程序并不现实。所以呢,在运行 Java 程序之前,我们需要对其进行一番转换。
这个转换具体是怎么操作的呢?当前的主流思路是这样子的,设计一个面向 Java 语言特性的虚拟机,并通过编译器将 Java 程序转换成该虚拟机所能识别的指令序列,也称 Java 字节码(也是class文件,class文件就是编译器编译之后供虚拟机解释执行的二进制字节码文件)。这里顺便说一句,之所以这么取名,是因为 Java 字节码指令的操作码(opcode)被固定为一个字节。
Java 虚拟机可以由硬件实现 ,但更为常见的是在各个现有平台(如 Windows_x64、Linux_aarch64)上提供软件实现。这么做的意义在于,一旦一个程序被转换成 Java 字节码,那么它便可以在不同平台上的虚拟机实现里运行。这也就是我们经常说的“一次编写,到处运行”。
虚拟机的另外一个好处是它带来了一个托管环境(Managed Runtime)。这个托管环境能够代替我们处理一些代码中冗长而且容易出错的部分。其中最广为人知的当属自动内存管理与垃圾回收,这部分内容甚至催生了一波垃圾回收调优的业务。
除此之外,托管环境还提供了诸如数组越界、动态类型、安全权限等等的动态检测,使我们免于书写这些无关业务逻辑的代码。Java 虚拟机具体是怎样运行 Java 字节码的?
下面将以标准 JDK 中的 HotSpot 虚拟机为例,从虚拟机以及底层硬件两个角度,来分析Java 虚拟机具体是怎么运行 Java 字节码的。
从虚拟机视角来看,执行 Java 代码首先需要将它编译而成的 class 文件加载到 Java 虚拟机中。加载后的 Java 类会被存放于方法区(Method Area)中。实际运行时,虚拟机会执行方法区内的代码。
Java 虚拟机在内存中划分出堆和栈来存储运行时数据。不同的是,Java 虚拟机会将栈细分为面向 Java 方法的 Java 方法栈,面向本地方法(用 C++ 写的 native 方法)的本地方法栈,以及存放各个线程执行位置的 PC 寄存器(也叫程序计数器)。

在运行过程中,每当调用进入一个 Java 方法,Java 虚拟机会在当前线程的 Java 方法栈中生成一个栈帧,用以存放局部变量以及字节码的操作数。这个栈帧的大小是提前计算好的,而且 Java 虚拟机不要求栈帧在内存空间里连续分布。
当退出当前执行的方法时,不管是正常返回还是异常返回,Java 虚拟机均会弹出当前线程的当前栈帧,并将之舍弃。
从硬件视角来看,Java 字节码无法直接执行。因此,Java 虚拟机需要将字节码翻译成机器码。
在 HotSpot 里面,上述翻译过程有两种形式:第一种是解释执行,即逐条将字节码翻译成机器码并执行;第二种是即时编译(Just-In-Time compilation,JIT),即将一个方法中包含的所有字节码编译成机器码后再执行。

前者的优势在于无需等待编译,而后者的优势在于实际运行速度更快。HotSpot 默认采用混合模式,综合了解释执行和即时编译两者的优点。它会先解释执行字节码,而后将其中反复执行的热点代码,以方法为单位进行即时编译。
Java 虚拟机的运行效率究竟是怎么样的?HotSpot 采用了多种技术来提升启动性能以及峰值性能,刚刚提到的即时编译便是其中最重要的技术之一。
即时编译建立在程序符合二八定律的假设上,也就是百分之二十的代码占据了百分之八十的计算资源。
对于占据大部分的不常用的代码,我们无需耗费时间将其编译成机器码,而是采取解释执行的方式运行;另一方面,对于仅占据小部分的热点代码,我们则可以将其编译成机器码,以达到理想的运行速度。
理论上讲,即时编译后的 Java 程序的执行效率,是可能超过 C++ 程序的。这是因为与静态编译相比,即时编译拥有程序的运行时信息,并且能够根据这个信息做出相应的优化。
举个例子,我们知道虚方法是用来实现面向对象语言多态性的。对于一个虚方法调用,尽管它有很多个目标方法,但在实际运行过程中它可能只调用其中的一个。
这个信息便可以被即时编译器所利用,来规避虚方法调用的开销,从而达到比静态编译的 C++ 程序更高的性能。
为了满足不同用户场景的需要,HotSpot 内置了多个即时编译器:C1、C2 和 Graal。Graal 是 Java 10 正式引入的实验性即时编译器。
之所以引入多个即时编译器,是为了在编译时间和生成代码的执行效率之间进行取舍。C1 又叫做 Client 编译器,面向的是对启动性能有要求的客户端 GUI 程序,采用的优化手段相对简单,因此编译时间较短。
C2 又叫做 Server 编译器,面向的是对峰值性能有要求的服务器端程序,采用的优化手段相对复杂,因此编译时间较长,但同时生成代码的执行效率较高。
从 Java 7 开始,HotSpot 默认采用分层编译的方式:热点方法首先会被 C1 编译,而后热点方法中的热点会进一步被 C2 编译。
为了不干扰应用的正常运行,HotSpot 的即时编译是放在额外的编译线程中进行的。HotSpot 会根据 CPU 的数量设置编译线程的数目,并且按 1:2 的比例配置给 C1 及 C2 编译器。
在计算资源充足的情况下,字节码的解释执行和即时编译可同时进行。编译完成后的机器码会在下次调用该方法时启用,以替换原本的解释执行。

总结:
Java 代码被虚拟机编译成字节码文件(class文件),然后再加载到Java 虚拟机中。加载后的 java 类会被存放于方法区(Method Area)中,Java 虚拟机将运行时内存区域划分为五个部分,分别为方法区、堆、PC 寄存器、Java 方法栈和本地方法栈。
Java 程序编译而成的 class 文件,需要先加载至方法区中,方能在 Java 虚拟机中运行。
为了提高运行效率,标准 JDK 中的 HotSpot 虚拟机采用的是一种混合执行的策略。
它会解释执行 Java 字节码,然后会将其中反复执行的热点代码,以方法为单位进行即时编译,翻译成机器码后直接运行在底层硬件之上。

01 | Java代码是如何运行相关推荐

  1. Java程序员必备基础:Java代码是怎么运行的?

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:一个线程池 bug 引发的 GC 思考!个人原创+1博客:点击前往,查看更多 链接:https://segmen ...

  2. 给定下面的java代码_则运行_会产生类型的异常_JavaSE_笔试题_单选选择题

    JavaSE_笔试题_单选选择题1 1. 下面哪一种描述是正确的()? A:abstract修饰符可修饰字段.方法和类. B:抽象方法的body部分必须用一对大括号{}包住. C:声明抽象方法,大括号 ...

  3. java代码是怎么运行的_Java代码是如何运行起来的?

    目录 1.编译 写好:".java"代码后,会通过编译器将代码编译成.class后缀的字节码文件 Java是平台无关的,实现语言无关性的基础就是虚拟机和字节码存储格式 只要编译器按 ...

  4. Java代码是如何运行的?

    引言 自己的主业也是java,所以多写java文章还是很有必要的,本篇文章来源于互联网(过于先进,不便展示),读完本篇文章你将了解什么是Java语言以及与其它语言的区别.初步了解java代码的运行过程 ...

  5. Java代码是怎么运行的?

    <深入拆解Java虚拟机>学习笔记 专栏地址:http://gk.link/a/1018S 个人博客:http://laijianfeng.org Java 和 C++ 在运行方式上的区别 ...

  6. java代码是如何运行和部署的?

    我们的class的文件是如何形成的? class文件也称为字节码文件,能够被机器所能识别的二进制流,是javac将.java文件编译之后得到的文件. Class文件又是如何被执行的? class文件是 ...

  7. java代码如何能运行起来_Java代码如何运行

    Java作为高级语言,高度抽象,无法直接运行在机器上,这样就必须设计一个面向Java语言特征的虚拟机,并通过编译器将Java程序转化成虚拟机所能识别的指令序列,也成Java字节码. Java 虚拟机将 ...

  8. java代码没错却运行不了_Java代码没错误,tomcat能正常运行,但是我的项目主页却一直显示不了,显示404错误...

    重新在别人的电抄脑上配置一次环境变量bai 配置环境变量 点击du计算机->高级系zhi统设置->环境变量dao-> 在第一个中新建一个 变量:classpath 值:.;(记住是分 ...

  9. java中有二叉树类吗,二叉树小结(附Java代码可直接运行)

    二叉树常见类型 1.满二叉树 一棵二叉树的结点要么是叶子结点,要么它有两个子结点(如果一个二叉树的层数为K,且结点总数是(2^k) -1,则它就是满二叉树.) 层数与此层节点数的对应关系:第K层,节点 ...

最新文章

  1. OpenCV2.4.X怎样使开发出来的exe文件或软件可独立运行?
  2. 万字长文搞定C语言指针
  3. 【数学建模】图论模型-Floyd算法(最优化)
  4. 分组查询最晚一条数据(ORACLE)
  5. C++ primer 第10章 泛型算法
  6. php中$stu_by,PHP基础案例二:计算学生年龄
  7. 微信公众号开发之微信服务器配置
  8. 2017.3.30 寿司晚宴 失败总结
  9. inputtextarea表单提示文字
  10. 数据库系统原理选择题
  11. elipse开发android 如何查看报错信息
  12. 【优化算法】混沌单纯形法算子布谷鸟搜索优化算法【含Matlab源码 1193期】
  13. 你不知道网络安全有多严峻
  14. 解决输入框中文英文长度限制不同的情况
  15. 关闭和重启脚本合二为一orderlist.sh
  16. Win7开自带的虚拟WIFI
  17. Feature Enhancement Network: A Refined Scene Text Detector
  18. 将多个csv文件合并成一个
  19. android 获取类对象(代码片段)
  20. 4.1 理解层叠分类器的检测原理

热门文章

  1. JavaWeb - 联系人信息管理综合练习 外链图片还未修改
  2. Java网络编程和NIO详解开篇:Java网络编程基础
  3. c语言制作猜数游戏教程,C语言实现猜数游戏
  4. 【3D计算机视觉】从PointNet到PointNet++理论及pytorch代码
  5. 3D视觉(四):ORB特征提取与匹配
  6. 论文阅读”Multigraph Fusion for Dynamic Graph Convolutional Network“(TNNLS2022)
  7. JAVA计算机毕业设计ipq管理系统Mybatis+系统+数据库+调试部署
  8. 遗传算法:交叉算法提高种群收敛速度
  9. this project needs to migrate WTP metadata 异常解决办法
  10. Tian Ji -- The Horse Racing(田忌赛马)