Java代码运行的方式

1:在开发工具中运行
2:双击 jar 文件运行
3:在命令行中运行
4:在网页中运行

上述运行方式都离不开 JRE,也就是 Java 运行时环境。实际上 JRE 仅包含运行 Java 程序的必须组件,包括 Java 虚拟机以及 Java 核心类库等。Java 程序员经常接触到的 JDK 同样包含了 JRE,并且还附带了一系列开发和诊断工具。

为什么 Java 要在虚拟机里运行

Java 是一门高级程序语言,语法复杂,抽象程度高,因此直接在硬件上运行并不现实。所以,在 Java 程序运行之前,需要对其进行转换。

设计一个面向 Java 语言的特性的虚拟机,并通过编译器将 Java 程序转换成该虚拟机所能识别的指令程序,也叫 Java 字节码。之所以叫做字节码,是因为 Java 字节码指令的操作码被固定为一个字节。

使用虚拟机的好处

Java 虚拟机也可以由硬件直接实现,但是更为常见的是基于软件实现。

如果一个 Java 程序被转换成 Java 字节码,那么他便可以在不同平台上的 Java 虚拟机实现里运行。这就是通常所说的:一次编译,到处运行。

虚拟机的另一个好处就是它提供了一个托管环境。这个托管环境代替我们处理一些代码中冗长而且容易出错的代码。最明显的使用就是自动内存管理和垃圾回收。托管环境还提供了诸如数组越界,动态类型,安全权限等等动态监测。

Java 虚拟机如何运行 Java 字节码

下面以标准 JDK 中的 HotSpot 虚拟机为例,从虚拟机以及底层硬件两个角度进行分析。

从虚拟机的视角来看,首先将 Java 代码编译成 class 文件加载到 Java 虚拟机中。加载后的 Java 类会被存放于方法区,实际运行时,虚拟机会执行方法区的代码。

Java 虚拟机在内存中划分出堆和栈来存储运行时的数据。对于栈, Java 虚拟机会把其细分为面向 Java 方法的 Java 方法栈,面向本地方法(用 C++ 写的 native 方法)的本地方法栈,以及存放各个线程执行位置的 PC 寄存器。

在虚拟机运行过程中,每当调用进入一个 Java 方法, Java 虚拟机会在当前线程的 Java 方法栈中生成一个栈帧,用以存放局部变量以及字节码的操作数。

当退出当前执行的方法时,不管是正常返回还是异常返回,Java 虚拟机均会弹出当前线程的当前栈帧,将之舍弃。

从硬件的视角来看,Java 字节码无法直接执行,因此 Java 虚拟机需要将字节码翻译成机器码。

翻译的形式有两种,一种是解释执行,即逐条将字节码翻译成机器码执行;一种是即时编译,即将一个方法中包含的所有字节码编译成机器码后再执行。

解释执行的优势在于无需等待编译,及时编译的优势在于实际运行速度会更快。HotSpot 默认采用混合模式,综合了解释执行和即时编译两者的优点。它会先解释执行字节码,而后将其中反复执行的热点代码,以方法为单位进行即时编译。

Java 虚拟机的运行效率

HotSpot 采用了多种技术来提升启动性能以及峰值性能,即时编译就是其中最重要的技术之一。

为了满足不同用户场景的需要,HotSpot 内置了多个即时编译器:C1,C2 和 Graal。Graal 是 Java 10 正式引入的实验性即时编译器,后续再总结。引入多个即时编译器,是为了在编译时间和生成代码的执行效率之间进行取舍。

C1 又叫做 Client 编译器,面向的是对启动性能有要求的客户端 GUI 程序,采用的优化手段相对简单,因此编译时间较短。

C2 又叫做 Server 编译器,面向的是对峰值性能有要求的服务器端程序,采用的优化手段相对复杂,因此编译时间较长,但生成代码的执行效率较高。

从 Java 7 开始,HotSpot 默认次用分层编译的方式:热点方法首先会被 C1 编译,而后热点方法中的热点会进一步被 C2 编译。

为了不干扰应用正常的运行,HotSpot 的即时编译是放在额外的编译线程中进行的。HotSpot 会根据 CPU 的数量设置编译线程的数目,并且按 1:2 的比例分配给 C1 和 C2 编译器。

问答

Q:对于发布一次就长时间运行的程序,为什么不选择直接将 Java 字节码编译成机器码

事实上 JVM 却是有考虑做 AOT 的这种事情。AOT 能够在线下将 Java 字节码编译成机器码,主要用来解决启动性能不好的问题。其实线下编译和即时编译都一样,至多一两个小时后该编译的都已经编译完成了。另外,即时编译器因为有程序运行时信息,优化效果更好,也就是说峰值性能更好。

Q:如何区分热点代码和非热点代码

关于热点代码的统计有两种算法:一种是基于采样的热点探测,一种是基于计数器的热点探测。基于计数器的热点探测又有两个计数器:一种是方法调用计数器,一种是回边计数器,他们在 C1 和 C2 中有不同的阈值。默认的分层编译应该是达到两千调用 C1,达到一万五调用 C2。一般采用的都是基于计数器的热点探测。

Q:对于 JVM 的及时编译,当方法体中有很多 if,else if 这样的判断,如何编译

JVM 有两种编译方式,一种是对整个方法进行编译,一种是对热循环进行编译。无论哪种,都要比 if else 的粒度大。

总结

本文创作灵感来源于 极客时间 郑雨迪老师的《深入拆解 Java 虚拟机》课程,通过课后反思以及借鉴各位学友的发言总结,现整理出自己的知识架构,以便日后温故知新,查漏补缺。

关注本人公众号,第一时间获取最新文章发布,每日更新一篇技术文章。

01 Java 代码是怎么运行的的更多相关文章

  1. 听说你还不知道Java代码是怎么运行的?

    作为一名Java程序员,我们需要知道Java代码是怎么运行的.最近复习了深入理解Java虚拟机这本书,做了一下笔记,希望对大家有帮助,如果有不正确的地方,欢迎提出,感激不尽. java 代码运行主要流 ...

  2. JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇

    JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇 作为一个使用Java语言开发的程序员,我们都知道,要想运行Java程序至少需要安装JRE(安装JDK也没问题).我们也知道我们Java程序 ...

  3. 《深入理解Java虚拟机》-Java代码是如何运行的

    问题一:Java与C++区别 1.Java需要运行时环境,包括Java虚拟机以及Java核心类库等. 2.C++无需额外的运行时,通常编译后的代码可以让机器直接读取,即机器码 问题一:Java为什么要 ...

  4. Java代码是怎么运行的

    前言.... 作为一名 Java 程序员,你应该知道,Java 代码有很多种不同的运行方式.比如说可以在开发工具中运行,可以双击执行 jar 文件运行,也可以在命令行中运行,甚至可以在网页中运行.当然 ...

  5. Java代码在本地运行没有问题。上传到阿里云服务器后。出现了中文乱码解决

    java -Dfile.encoding=UTF-8 -jar project.jar

  6. MVC框架的理解(配置文件一次编写,所有的java代码都可以运行)

  7. JAVA_HOME path classpath 以及cmd编译运行java代码

    JAVA_HOME PATH CLASSPATH 三者的区别:安装完jdk之后,首先在环境变量里面添加JAVA_HOME ,例如安装路径为C:\Program Files\Java\jdk1.6.0_ ...

  8. 用DOS命令来运行Java代码

    用DOS命令来运行Java代码.. ----------------- Demo.java public class Demo { public static void main(String[] a ...

  9. Java基础之用记事本编辑java代码运行,并且打成jar包后运行

    使用记事本写java代码 1.在d盘新建一个记事本,名字叫做zhanzhuang.java,会询问不可用,是否继续,点击是 2.在里面编辑就如下内容,注意文件的名字要和 class 后面的名字相对应 ...

随机推荐

  1. Ubuntu 12.04源

    deb http://ubuntu.uestc.edu.cn/ubuntu/ precise main restricted universe multiverse deb http://ubuntu ...

  2. python3发送邮件02(简单例子,带附件)

    #!/usr/bin/env python# -*- coding:UTF-8 -*- import osimport smtplibfrom email.header import Headerfr ...

  3. node执行cmd命令方法

    var cmd='tasklist';//获取 子进程模块的exec方法,用于执行cmd命令var exec = require('child_process').exec; //运行 定义的cmd命 ...

  4. HDU 4055 Number String(DP计数)

    题意: 给你一个含n个字符的字符串,字符为'D'时表示小于号,字符为“I”时表示大于号,字符为“?”时表示大小于都可以.比如排列 {3, 1, 2, 7, 4, 6, 5} 表示为字符串 DIIDID ...

  5. COGS 2104. [NOIP2015]神奇的幻方

    ★   输入文件:2015magic.in   输出文件:2015magic.out   简单对比时间限制:1 s   内存限制:256 MB 模拟 一开始数组开小了.. 屠龙宝刀点击就送 #incl ...

  6. 将SQL2008升级为SQL2008 r2

    我的SQL2008版本信息 Microsoft SQL Server Management Studio     10.0.1600.22 ((SQL_PreRelease).080709-1414 ...

  7. 如何将S/4HANA系统存储的图片文件用Java程序保存到本地

    我在S/4HANA的事务码MM02里为Material维护图片文件作为附件: 通过如下简单的ABAP代码即可将图片文件的二进制内容读取出来: REPORT zgos_api. DATA ls_appl ...

  8. C#注册表操作类(完整版)

    下面贴出自己用C#写的注册表操作类,欢迎大家拍砖! 1.注册表基项静态域 1 /// <summary> 2 /// 注册表基项静态域 3 /// 4 /// 主要包括: 5 /// 1. ...

  9. [uestc oj]H - 邱老师选妹子

    H - 邱老师选妹子 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submi ...

  10. cdoj 414 八数码 (双向bfs+康拓展开,A*)

    一道关乎人生完整的问题. DBFS的优越:避免了结点膨胀太多. 假设一个状态结点可以扩展m个子结点,为了简单起见,假设每个结点的扩展都是相互独立的. 分析:起始状态结点数为1,每加深一层,结点数An ...