Java代码是怎么运行的

17 篇文章 0 订阅
订阅专栏

Java代码有很多运行方式。

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

当然,上述运行方式都离不开JRE, 也就是Java运行时环境。

JRE仅包含Java程序的必须组件,包括Java虚拟机以及Java核心类库等。

而我们Java程序员经常接触到的JDK(Java开发工具包)同样包含了JRE, 并且还附带了一系列开发、诊断工具。

然而,运行C++程序则无需额外的运行时环境,C++编译器往往把C++代码编译成CPU能够理解的机器码。

那么,既然C++的运行方式如此成熟,我们为什么要在JVM里运行Java代码呢?

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

Java作为一门高级程序语言,它的语法复杂,抽象程度也很高。因此在硬件上运行Java代码并不现实,所以运行Java程序之前,我们需要对其进行一番转换。

当前进行转换的主要思路是:设计一个面向Java语言特性的虚拟机,并通过编译器将Java程序转换层该虚拟机所能识别的指令序列(Java字节码)。之所以这么取名,是因为Java字节码指令的操作码被固定成一个字节。

Java虚拟机可以由硬件实现

https://en.wikipedia.org/wiki/Java_processor

当然,更多时候还是在各个现有平台(Windows_x64,Linux_aarch64)上提供软件实现。这么做的目的在于,一旦一个程序被编译成Java字节码,那么它变可以在不同平台上的虚拟机实现里运行。这也就是平时我们所说的Java的跨平台特性。

虚拟机的另外一个好处是它带来了一个托管环境(Managed Runtime)。这个托管环境能够代替我们处理一些代码中冗长而且容易出错的部分。其中最广为人知的当属自动内存管理与垃圾回收,这部分内容甚至催生了一波垃圾回收调优的业务。

除此之外,托管环境还提供了诸如数组越界,动态类型、安全权限等等的动态监测,使我们免于书写这些无关业务逻辑的代码。

Java虚拟机具体是怎么运行Java字节码的?

以标准JDK中的HotSpot虚拟机为例,从虚拟机和底层硬件两个角度,剖析该问题。

从虚拟机的角度来看,执行Java代码首先需要将它编译而成的class文件加载到Java虚拟机中。加载后的Java类会被存放于方法区(Method Area)中。实际运行时,虚拟机会执行方法区内的代码。

如果你熟悉X86的话,你会发现这和段式存储管理中的代码段类似。而且,Java虚拟机同样也会在内存中划分出堆和栈来存储运行时的数据。不同的是,Java虚拟机会将栈细分为面向Java方法的Java方法栈面向本地方法(用C++写的native方法)的本地方法栈,以及存放各个线程执行位置的PC寄存器

 

在运行过程中,每当调用进入一个Java方法,Java虚拟机会在当前线程的Java方法栈中生成一个栈帧,用以存放局部变量以及字节码的操作数。这个栈帧的大小是提前计算好的,而且Java虚拟机不要求栈帧在内存空间里连续分布。

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

在HotSpot里面,上述翻译过程有两种形式

  1. 解释执行,即逐条将字节码翻译成机器码并执行。
  2. 即时编译(Just-In-Time compilation, JIT), 即将一个方法中包含的所有字节码编译成机器码后再执行。

前者的优势是无需等待编译,而后者的优势在于实际的运行速度更快。

HotSpot默认采用混合模式,综合了解释执行和即时编译两者的优点。

它会首先解释字节码。然后将其中反复执行的热点代码,以方法为单位即时编译

Java虚拟机的运行效率究竟是怎么样的?

HotSpot采用了多种技术来提升峰值性能,上文提到的即时编译技术便是其中最重要的技术之一。

即时编译建立在程序符合二八定律的假设上。

二八定律:20%的代码占用了程序执行过程中80%的资源。

对于占据大部分的不常用的代码,我们无需耗费时间将其编译成机器码,而是采用解释执行的方式。

另一方面,对于仅占据小部分的热点代码,我们则可以将其编译成机器码,打到理想的运行速度。

理论上讲,即时编译后的Java程序的执行效率,是可以超过C++程序的。这是因为与静态编译相比,即时编译拥有程序的运行时信息,并且能够根据这个信息做出相应的优化。(实际上,编译时会插入一些有关jvm的代码)

举个例子,我们知道虚方法是用来实现面向对象语言多态性的。对于一个虚方法调用,尽管它有很多个目标方法,但在实际运行过程中他可能只调用了其中的一个,这个信息便可以被即时编译器所利用,来规避虚方法调用的开销从而达到比静态编译的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语言和Java虚拟机看待boolean类型的方式是否不同。

首先,撰写代码Foo.java


 
 
  1. public class Foo {
  2. public static void main(String[] args){
  3. boolean flag = true;
  4. if(flag)
  5. System.out.println( "Hello, Java!!");
  6. if(flag == true)
  7. System.out.println( "Hello, JVM!!!");
  8. }
  9. }

 
 
  1. javac Foo.java
  2. java Foo

显然,它的执行结果是:

Hello, Java!!
Hello, JVM!!!

我们使用asmtools.jar对其进行反汇编(此命令JDK7无法运行, 需要升级到JDK8)

下载地址: https://download.csdn.net/download/ti_an_di/10555815

java -cp ./asmtools.jar org.openjdk.asmtools.jdis.Main Foo.class > Foo.jasm.1
 
 

我们得到它的反汇编代码(在Foo.jasm.1 中)


 
 
  1. super public class Foo
  2. version 52:0
  3. {
  4. public Method "<init>": "()V"
  5. stack 1 locals 1
  6. {
  7. aload_0;
  8. invokespecial Method java/lang/Object. "<init>": "()V";
  9. return;
  10. }
  11. public static Method main: "([Ljava/lang/String;)V"
  12. stack 2 locals 2
  13. {
  14. iconst_1; //看这里
  15. istore_1;
  16. iload_1;
  17. ifeq L14;
  18. getstatic Field java/lang/System.out: "Ljava/io/PrintStream;";
  19. ldc String "Hello, Java!!";
  20. invokevirtual Method java/io/PrintStream.println: "(Ljava/lang/String;)V";
  21. L14: stack_frame_type append;
  22. locals_map int;
  23. iload_1;
  24. iconst_1;
  25. if_icmpne L27;
  26. getstatic Field java/lang/System.out: "Ljava/io/PrintStream;";
  27. ldc String "Hello, JVM!!!";
  28. invokevirtual Method java/io/PrintStream.println: "(Ljava/lang/String;)V";
  29. L27: stack_frame_type same;
  30. return;
  31. }
  32. } // end Class Foo

在运行指令

awk 'NR==1,/iconst_1/{sub(/iconst_1/, "iconst_2")} 1' Foo.jasm.1 > Foo.jasm
 
 

其作用是将Foo.jasm.1文件中第一个iconst_1 替换为iconst_2, 输出到文件Foo.jasm中


 
 
  1. super public class Foo
  2. version 52: 0
  3. {
  4. public Method "<init>": "()V"
  5. stack 1 locals 1
  6. {
  7. aload_0;
  8. invokespecial Method java/lang/Object. "<init>": "()V";
  9. return;
  10. }
  11. public static Method main: "([Ljava/lang/String;)V"
  12. stack 2 locals 2
  13. {
  14. iconst_2; //看这里
  15. istore_1;
  16. iload_1;
  17. ifeq L14;
  18. getstatic Field java/lang/System. out: "Ljava/io/PrintStream;";
  19. ldc String "Hello, Java!!";
  20. invokevirtual Method java/io/PrintStream.println: "(Ljava/lang/String;)V";
  21. L14: stack_frame_type append;
  22. locals_map int;
  23. iload_1;
  24. iconst_1;
  25. if_icmpne L27;
  26. getstatic Field java/lang/System. out: "Ljava/io/PrintStream;";
  27. ldc String "Hello, JVM!!!";
  28. invokevirtual Method java/io/PrintStream.println: "(Ljava/lang/String;)V";
  29. L27: stack_frame_type same;
  30. return;
  31. }
  32. } // end Class Foo

我们现在将flag的值由1改为了2, 将修改后的代码汇编到Foo.class文件中

java -cp ./asmtools.jar org.openjdk.asmtools.jasm.Main Foo.jasm
 
 

再次运行Foo类


 
 
  1. java Foo
  2. Hello, Java!!

可见JVM将true视为1, 不等于修改为2的flag,使用if_icmpne指令判断他们不相等,直接跳到L27执行,所以Hello, JVM!!!不会输出。而第一次判断是使用ifeq判断flag的值是否为0,所以Hello,Java!!会输出。

此文从极客时间专栏《深入理解Java虚拟机》搬运而来,撰写此文的目的:

  1. 对自己的学习总结归纳

  2. 此篇文章对想深入理解Java虚拟机的人来说是非常不错的文章,希望大家支持一下郑老师。

java代码-运行结果。
07-16
java代码-运行结果。
Java程序执行流程
weixin_58724261的博客
06-06 4851
Java程序的源代码需要经过编译器(例如javac)的编译,将其转换成字节码(即.class文件),这个过程称为编译。编译器会对源代码中的语法进行检查和优化,并生成可在JVM上运行的字节码文件。
Java运行过程
KEEP CODING
08-21 3238
Java编译器将java源文件(.java)转换成字节码文件(.class),类加载器(ClassLoader)将字节码文件加载进内存,然后进行字节码校验,最后Java 解释器翻译成机器码。
Python代码写好了怎么运行?_python代码怎么运行
最新发布
m0_59235508的博客
04-14 1322
Python代码写好了怎么运行?相信问这样问题的朋友一定是刚刚入门Python的初学者。本文就来为大家详细讲讲如何运行Python代码。一般来讲,运行Python代码的方式有两种,一是在Python交互式命令行下运行;另一种是使用文本编辑器,在命令行中直接运行。这两种方法各有优缺点,下面我们以hello world来举例,为大家打开Python学习的大门,现在就一起看看吧!
1、Java程序如何运行
ImBeen的博客
03-17 9718
1、Java程序如何运行 1.1 创建java文件,编写程序 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5OhhIkc9-1647494017223)(E:\JavaTypora\Test_0001\image-20220317120910960.png)] 1.2 选中所在目录,输入cmd+回车,出现黑框命令行 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lVQIbD49-1647494017225)(E:\JavaTypora\Tes
Java基础:Java运行原理
love_study1314的博客
02-07 1782
本文介绍Java运行原,包括JVM体系结构、Java方法调用原理等。
java如何编译、运行以及java数据类型
ryy1999的博客
10-12 5507
java如何编译、运行以及java数据类型 目录 一、java如何编译、运行 二、java数据类型 一、java如何编译、运行 1.先新建文件夹test,进入文件夹,新建test_1011.txt文件,将后缀改为.java文件。 二、使用步骤 1.引入库 代码如下(示例): import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import warnings warnings.
Java直接运行JS代码
09-27
Java直接运行JS代码样例 java中调用js脚本 java中直接调用js代码
java代码-试运行阶段
07-15
java代码-试运行阶段
俄罗斯方块JAVA代码
08-22
闲时无聊,用Java写了一个小时候经常玩的俄罗斯方块小游戏(里面有源代码和编译好的可执行jar包)。 运行环境jdk1.8 源码使用方法:打开eclipse,新建一个java project然后把tetris目录复制到project里的src目录下。
Java动态编译Java代码运行在内存中,并执行
01-30
通过java的ToolProvider创建JavaCompile,用来执行class源文件 * 4.创建DiagnosticCollector用来执行获取执行失败的错误结果 * 5.添加动态执行的编译环境 options 是个集合,添加内容,字符集,classpath等 * 6....
java应用打包运行的4种方法
penngo的专栏
12-11 6816
方法一是打成Jar,使用shell脚本启动是最常用的打包运行方式,打包发布不会存在兼容问题。运行时会显示两个进程:shell进程与java进程。 方法二是在方法一基础上,简化shell的启动方式,但是启动器需要在每个平台上编译一次。运行时会显示两个进程:启动器进程与java进程。 方法三是JDK自带的工具打包,与方法二相比,省掉自己编写启动器的工具。运行时会显示两个相同名称的应用进程。 方法四是目前新的方式,能显著提高性能,但由于应用使用反射等技术原因,可能需要手动编写反射类,与前边3种方法相比,有一点的上
Java代码运行过程
chengbo_eva的博客
06-08 2695
Java代码运行过程
如何执行代码
weixin_42602241的博客
12-30 1909
要执行代码,首先需要有一个代码编辑器或者集成开发环境(IDE)。常见的代码编辑器有 Sublime Text、Notepad++ 等,常见的 IDE 有 Visual Studio、Eclipse、PyCharm 等。 接下来,在代码编辑器或 IDE 中编写代码,保存文件后就可以执行了。执行的方式因语言而异。 对于脚本语言(如 Python、JavaScript、Perl 等),可以使用命令行工具...
读郑雨迪《深入拆解Java虚拟机》 -- 第一讲 Java代码是怎么运行
Ti_an_Di的博客
07-21 4730
本文转自https://time.geekbang.org/column/article/11289 Java代码有很多运行方式。 在开发工具中运行 双击jar文件运行 在命令行中运行 在网页中运行 当然,上述运行方式都离不开JRE, 也就是Java运行时环境。 JRE仅包含Java程序的必须组件,包括Java虚拟机以及Java核心类库等。 而我们Java程序员经常接触到的JDK(J...
Python代码写好了怎么运行
Python栈
06-07 1万+
Python代码写好了怎么运行?相信问这样问题的朋友一定是刚刚入门Python的初学者。本文就来为大家详细讲讲如何运行Python代码。一般来讲,运行Python代码的方式有两种,一是在Python交互式命令行下运行;另一种是使用文本编辑器,在命令行中直接运行。这两种方法各有优缺点,下面我们以hello world来举例,为大家打开Python学习的大门,现在就一起看看吧!
Java基础 - Java环境及编译运行原理
m0_46521939的博客
03-01 2090
Java组成可以理解为:“一个平台”:JVM;“一套工具”:编译;“一套库”:JDK;“一套规范”:Java代码和jvm指令集规范表。**
java文件如何运行
malacheese的博客
04-13 2830
名称.java文件先用 javac 名称.java 进行编译,生成 .class文件,在用 java 名称 生成结果。2.文件->设置文件编码->GBK;文件->保存 (因为命令行窗口的编码为GBK,需保持一致,不然会报错)1.在Sublime中:新建文件,另存为 D:\javacode\Hello.java。3.打开Hello.java文件所在位置,蓝色光标选中处输入cmd。文件所在位置出现Hello.class。(表示对Hello.java进行编译)此处Hello无需再加后缀.class。
Python代码的编写运行方式
热门推荐
nnn0245的博客
11-27 1万+
Python运行方式的详细教程
java代码快捷键运行
05-13
在 Eclipse 中,可以使用以下快捷键来运行 Java 代码: 1. 按下 "Ctrl + F11" 键,或者点击菜单栏中的 "Run" -> "Run" 选项。 2. 如果你要运行的是当前编辑器中的代码,可以按下 "Ctrl + Shift + F10" 键,或者点击菜单栏中的 "Run" -> "Run Last Launched" 选项。 3. 如果你想要运行代码的一部分,可以选中该部分代码后按下 "Ctrl + Shift + X" 键,或者点击菜单栏中的 "Run" -> "Run as Java Application" 选项。 以上是 Eclipse 中运行 Java 代码的快捷键,其他 IDE 也有类似的快捷键。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • org.apache.ibatis.exceptions.PersistenceException:解决方法 94966
  • Java如何输入不确定长度的数组 35603
  • 机器学习实战-数据预处理(异常值处理) 30322
  • JAVA中3种将byte转换为String的方法 28765
  • Java代码是怎么运行的 28495

分类专栏

  • DDD 1篇
  • zookeeper 1篇
  • 深入理解elasticsearch
  • Spring源码分析 3篇
  • hotspot源码分析
  • 深入理解Java虚拟机 5篇
  • SpringMVC实战教程 8篇
  • MyBatis源码解析 6篇
  • 深入理解kafka 1篇
  • Java并发编程教程 11篇
  • Spring实战教程 15篇
  • 学习方法总结 7篇
  • Java虚拟机 17篇
  • Java基础 16篇
  • Java并发编程 16篇
  • Java集合类 5篇
  • Android 36篇
  • 面试相关 11篇
  • MySQL 14篇
  • 数据结构与算法 31篇
  • 开发遇到的问题及解决汇总 27篇
  • Spring 36篇
  • MyBatis 8篇
  • 计算机网络 4篇
  • Netty 3篇
  • 爬虫 4篇
  • 网站架构 10篇
  • Linux / 操作系统 15篇
  • Redis 6篇
  • SpringBoot
  • Hadoop 7篇
  • Tomcat源码分析 5篇
  • 前端知识 2篇
  • 机器学习 1篇
  • Dubbo 6篇
  • Docker 1篇
  • 消息队列 5篇
  • Nginx 1篇

最新评论

  • 基于SpringBoot+Mybatis+Thymeleaf商品信息管理系统

    没有海绵宝宝的小蜗: java: JPS 增量注解进程已禁用。部分重新编译的编译结果可能不准确。使用构建进程“jps.track.ap.dependencies”VM 标志启用/禁用增量注解处理环境。 java: java.lang.ExceptionInInitializerError com.sun.tools.javac.code.TypeTags java: java.lang.ExceptionInInitializerError 这是为啥

  • org.apache.ibatis.exceptions.PersistenceException:解决方法

    练佳子: 我也是,太难了

  • 堆外内存(直接内存)

    DK363787493: 连哪些内存是用户空间,哪些是内核空间都搞不清楚,严重误人子弟

  • 关于JMH运行ERROR: transport error 202: connect failed: Connection refused ERROR解决

    木木是林?: 牛逼,大佬有点牛逼

  • 基于SpringBoot+Mybatis+Thymeleaf商品信息管理系统

    在云端123: 试一下在pom.xml加上<mysql.version>5.2<mysql.version> 改为你本地mysql版本号,并且确保配置文件的账户密码是改为你本地数据库的账户密码

您愿意向朋友推荐“博客详情页”吗?

  • 强烈不推荐
  • 不推荐
  • 一般般
  • 推荐
  • 强烈推荐
提交

最新文章

  • 向上汇报模板
  • 通俗易懂讲解IO模型
  • 结构化思维
2022年1篇
2020年9篇
2019年29篇
2018年44篇
2017年218篇

目录

目录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

哆哆女性网郑州市网站的制作方法直播cctv-1魏姓男起名郭字起名字男孩名字周易类似的书孤独的野兽梦想三国破解版大全商丘火球庄姓男孩起名95分以上建设开发网站公司周易起网名免费豪华中学设施拆除周公解梦梦见白老虎七画起名吉利有什么字何姓起名字啊青年才俊电子签名具有法律效率吗速度与激情9电影天堂公司起名代表两个的字网站建设相关文章生鲜店铺起名的网页设计好的网站免费起名缺火的名字永城教师资格证查询恒盛皇家花园欧阳起名男孩的名字昆明购物网站建设网站建设西班牙语如何优化网站性能周易起名网怎么样好不好淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻不负春光新的一天从800个哈欠开始有个姐真把千机伞做出来了国产伟哥去年销售近13亿充个话费竟沦为间接洗钱工具重庆警方辟谣“男子杀人焚尸”男子给前妻转账 现任妻子起诉要回春分繁花正当时呼北高速交通事故已致14人死亡杨洋拄拐现身医院月嫂回应掌掴婴儿是在赶虫子男孩疑遭霸凌 家长讨说法被踢出群因自嘲式简历走红的教授更新简介网友建议重庆地铁不准乘客携带菜筐清明节放假3天调休1天郑州一火锅店爆改成麻辣烫店19岁小伙救下5人后溺亡 多方发声两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#青海通报栏杆断裂小学生跌落住进ICU代拍被何赛飞拿着魔杖追着打315晚会后胖东来又人满为患了当地回应沈阳致3死车祸车主疑毒驾武汉大学樱花即将进入盛花期张立群任西安交通大学校长为江西彩礼“减负”的“试婚人”网友洛杉矶偶遇贾玲倪萍分享减重40斤方法男孩8年未见母亲被告知被遗忘小米汽车超级工厂正式揭幕周杰伦一审败诉网易特朗普谈“凯特王妃P图照”考生莫言也上北大硕士复试名单了妈妈回应孩子在校撞护栏坠楼恒大被罚41.75亿到底怎么缴男子持台球杆殴打2名女店员被抓校方回应护栏损坏小学生课间坠楼外国人感慨凌晨的中国很安全火箭最近9战8胜1负王树国3次鞠躬告别西交大师生房客欠租失踪 房东直发愁萧美琴窜访捷克 外交部回应山西省委原副书记商黎光被逮捕阿根廷将发行1万与2万面值的纸币英国王室又一合照被质疑P图男子被猫抓伤后确诊“猫抓病”

哆哆女性网 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化