深入拆解Java虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
立即订阅
28017 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 为什么我们要学习Java虚拟机?
免费
模块一:Java虚拟机基本原理 (12讲)
01 | Java代码是怎么运行的?
02 | Java的基本类型
03 | Java虚拟机是如何加载Java类的?
04 | JVM是如何执行方法调用的?(上)
05 | JVM是如何执行方法调用的?(下)
06 | JVM是如何处理异常的?
07 | JVM是如何实现反射的?
08 | JVM是怎么实现invokedynamic的?(上)
09 | JVM是怎么实现invokedynamic的?(下)
10 | Java对象的内存布局
11 | 垃圾回收(上)
12 | 垃圾回收(下)
模块二:高效编译 (12讲)
【工具篇】 常用工具介绍
13 | Java内存模型
14 | Java虚拟机是怎么实现synchronized的?
15 | Java语法糖与Java编译器
16 | 即时编译(上)
17 | 即时编译(下)
18 | 即时编译器的中间表达形式
19 | Java字节码(基础篇)
20 | 方法内联(上)
21 | 方法内联(下)
22 | HotSpot虚拟机的intrinsic
23 | 逃逸分析
模块三:代码优化 (10讲)
24 | 字段访问相关优化
25 | 循环优化
26 | 向量化
27 | 注解处理器
28 | 基准测试框架JMH(上)
29 | 基准测试框架JMH(下)
30 | Java虚拟机的监控及诊断工具(命令行篇)
31 | Java虚拟机的监控及诊断工具(GUI篇)
32 | JNI的运行机制
33 | Java Agent与字节码注入
模块四:黑科技 (3讲)
34 | Graal:用Java编译Java
35 | Truffle:语言实现框架
36 | SubstrateVM:AOT编译框架
尾声 (1讲)
尾声 | 道阻且长,努力加餐
深入拆解Java虚拟机
登录|注册

01 | Java代码是怎么运行的?

郑雨迪 2018-07-20
我们学院的一位教授之前去美国开会,入境的时候海关官员就问他:既然你会计算机,那你说说你用的都是什么语言吧?
教授随口就答了个 Java。海关一看是懂行的,也就放行了,边敲章还边说他们上学那会学的是 C+。我还特意去查了下,真有叫 C+ 的语言,但是这里海关官员应该指的是 C++。
事后教授告诉我们,他当时差点就问海关,是否知道 Java 和 C++ 在运行方式上的区别。但是又担心海关官员拿他的问题来考别人,也就没问出口。那么,下次你去美国,不幸地被海关官员问这个问题,你懂得如何回答吗?
作为一名 Java 程序员,你应该知道,Java 代码有很多种不同的运行方式。比如说可以在开发工具中运行,可以双击执行 jar 文件运行,也可以在命令行中运行,甚至可以在网页中运行。当然,这些执行方式都离不开 JRE,也就是 Java 运行时环境。
实际上,JRE 仅包含运行 Java 程序的必需组件,包括 Java 虚拟机以及 Java 核心类库等。我们 Java 程序员经常接触到的 JDK(Java 开发工具包)同样包含了 JRE,并且还附带了一系列开发、诊断工具。
然而,运行 C++ 代码则无需额外的运行时。我们往往把这些代码直接编译成 CPU 所能理解的代码格式,也就是机器码。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入拆解Java虚拟机》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(174)

  • jiaobuchongจุ๊บ 置顶
    对老师写的那段 awk 不懂得可参考:
    https://blog.csdn.net/jiaobuchong/article/details/83037467
    2018-10-14
    54
  • 小名叫大明 置顶
    受益匪浅,多谢老师。

    请教老师一个问题,网上我没有搜到。

    服务器线程数爆满,使用jstack打印线程堆栈信息,想知道是哪类线程数太多,但是堆栈里全是一样的信息且没有任何关键信息,是哪个方法创建的,以及哪个线程池的都看不到。

    如何更改打印线程堆栈信息的代码(动态)让其打印线程池信息呢?
    2018-07-26
    27
  • 东方
    jvm把boolean当做int来处理

    flag = iconst_1 = true

    awk把stackframe中的flag改为iconst_2

    if(flag)比较时ifeq指令做是否为零判断,常数2仍为true,打印输出

    if(true == flag)比较时if_cmpne做整数比较,iconst_1是否等于flag,比较失败,不再打印输出


    作者回复: 字节码高手!

    2018-07-20
    320
  • かっこいすぎる郑一凡
    我想问下,JVM是怎么区别出热点代码和非热点代码的?
    2018-07-20
    3
    78
  • 醉人
    解释执行 执行时才翻译成机器指令,无需保存不占内存。但即时编译类似预编译,编译之后的指令需要保存在内存中,这种方式吃内存,按照二八原则这种混合模式最恰当的,热点代码编译之后放入内存避免重复编译,而其他运行次数较少代码则解释执行,避免占用过多内存
    2018-07-20
    76
  • novembersky
    文中提到虚拟机会把部分热点代码编译成机器码,我有个疑问,为什么不把java代码全部编译成机器码?很多服务端应用发布频率不会太频繁,但是对运行时的性能和吞吐量要求较高。如果发布或启动时多花点时间编译,能够带来运行时的持久性能收益,不是很合适么?

    作者回复: 问得好!事实上JVM确实有考虑做AOT (ahead of time compilation) 这种事情。AOT能够在线下将Java字节码编译成机器码,主要是用来解决启动性能不好的问题。

    对于这种发布频率不频繁(也就是长时间运行吧?)的程序,其实选择线下编译和即时编译都一样,因为至多一两个小时后该即时编译的都已经编译完成了。另外,即时编译器因为有程序的运行时信息,优化效果更好,也就是说峰值性能更好。

    2018-07-20
    71
  • MARK
    作业终于做出来~\(≧▽≦)/~喜大普奔
    asmtools下载地址:
    https://adopt-openjdk.ci.cloudbees.com/view/OpenJDK/job/asmtools/lastSuccessfulBuild/artifact/asmtools-6.0.tar.gz;
    先是在window环境里,awk不能使用,看https://zh.wikipedia.org/wiki/Awk,AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一,于是转战Linux,
    [root@localhost cqq]# javac Foo.java
    [root@localhost cqq]# java Foo
    Hello,Java
    Hello,JVM
    [root@localhost cqq]# java -cp /cqq/asmtools.jar org.openjdk.asmtools.jdis.Main Foo.class>Foo.jasm.1
    [root@localhost cqq]# ls
    asmtools.jar Foo.class Foo.jasm.1 Foo.java
    [root@localhost cqq]# vi Foo.jasm.1
    [root@localhost cqq]# awk 'NR==1,/iconst_1/{sub(/iconst_1/,"iconst_2")} 1' Foo.jasm.1>Foo.jasm
    [root@localhost cqq]# java -cp /cqq/asmtools.jar org.openjdk.asmtools.jasm.Main Foo.jasm
    [root@localhost cqq]# java Foo
    Hello,Java
    结果为啥是这个看点赞第一的高手;
    另外asmtools使用方式还可以这样子:
    java -jar asmtools.jar jdis Foo.class>Foo.jasm.1
    java -jar asmtools.jar jasm Foo.jasm
    2018-07-25
    66
  • 掌心童话
    我只想问,你就没有教授的担忧?万一我拿今天的知识点去问面试者,答不上来咋办?
    2018-07-21
    36
  • godtrue
    1:为什么使用JVM?
    1-1:可以轻松实现Java代码的跨平台执行
    1-2:JVM提供了一个托管平台,提供内存管理、垃圾回收、编译时动态校验等功能
    1-3:使用JVM能够让我们的编程工作更轻松、高效节省公司成本,提示社会化的整体快发效率,我们只关注和业务相关的程序逻辑的编写,其他业务无关但对于编程同样重要的事情交给JVM来处理

    2:听完此节的课程的疑惑(之前就没太明白,原期待听完后不再疑惑的)
    2-1:Java源代码怎么就经过编译变成了Java字节码?
    2-2:JVM怎么就把Java字节码加载进JVM内了?先加载那个类的字节码?它怎么定位的?拿到后怎么解析的?不会整个文件放到一个地方吧?使用的时候又是怎么找到的呢?这些感觉还是黑盒
    2-3:JVM将内存区域分成堆和栈,然后又将栈分成pc寄存器、本地方法栈、Java方法栈,有些内存空间是线程可共享的,有些是线程私有的。现在也了解不同的内存区块有不同的用处,不过他们是怎么被划分的哪?为什么是他们,不能再多几种或少几种了吗?共享的内存区和私有的又是怎么控制的哪?

    作者回复: 总结得非常细致!
    2-1 其实是这样的,JVM接收字节码,要运行在JVM上只能选择转化为字节码。要是不想在JVM上跑,可以选择直接转化为机器码。

    2-2 类加载会在第三篇详细介绍。

    2-3 具体的划分都是实现细节。你也可以选择全部冗杂在一起。但是这样子做性能较高,因为线程私有的可以不用同步。

    2018-07-24
    30
  • Ryan-Hou
    在为什么Java要在虚拟机里执行这一节您提到,java语法复杂,抽象度高,直接通过硬件来执行不现实,但是同样作为高级语言为什么C++就可以呢?这个理由作为引入虚拟机这个中间层的原因不是很充分吧

    作者回复: 多谢指出!这里的直接运行指的是不经过任何转换(编译),直接在硬件上跑。即便是C++,也不可以直接运行。

    C++的策略是直接编译成目标架构的机器码,Java的策略是编译成一个虚拟架构的机器码。这个虚拟架构可以有物理实现(可以搜Java processor),也可以是软件实现,也就是我们经常接触到的JRE。

    2018-07-20
    27
  • 周仕林
    看到有人说热点代码的区别,在git里面涉及到的热点代码有两种算法,基于采样的热点探测和基于计数器的热点探测。一般采用的都是基于计数器的热点探测,两者的优缺点百度一下就知道了。基于计数器的热点探测又有两个计数器,方法调用计数器,回边计数器,他们在C1和C2又有不同的阈值。😂😂

    作者回复: 谢谢!

    2018-07-23
    1
    24
  • J
    在Windows使用不了awk工具(貌似有代替方案),所以结合其他小伙伴的答案和自己的思考,答案整理如下:
    小作业的过程是:
    1、写Java代码,生成java文件
    2、将java文件编译成class文件(字节码)
    3、执行字节码,输出两个Hello,world!
    4、使用asmtool工具将class文件生成jasm文件
    5、使用awt工具将jasm文件stackframe的flag改为iconst_2
    6、再次使用asmtool工具将jasm文件恢复成class文件
    7、执行字节码,输出一个Hello, world!
    由于Java虚拟机将boolean类型看成0或者1,在步骤5中将源代码中的flag修改成2,于是在步骤7中的运行过程中,if(2),true,执行输出;if(2 == 1),结果为false,不执行输出。
    2018-12-25
    16
  • 尔东
    1.Java代码首先编译为class文件,然后通过java虚拟机加载到方法区。Java虚拟机是一个独立的进程,执行方法区的代码。
    2.Java虚拟机把内存分为堆栈两种形式来存储运行时数据,包括线程共有的方法区和堆,以及线程私有的pc计数器,方法栈,naive方法栈
    3.Java虚拟机将字节码翻译成机器码执行的方法有两种,一种是解释执行,即逐条将字节码翻译成机器码并执行;第二种是即时编译,即将一个方法包含的所有字节码编译成机器码后再执行
    4.解释执行的好处是无需等待编译,即时编译的好处是速度更快。这里编译的概念并不是代码编译为字节码,而是字节码编译为机器码,字节码编译为机器码是由java虚拟机在运行程序的时候才会去做的,所以是运行时的开销。热点代码会通过即时编译来执行。
    5.HotSpot内置了多个即时编译器,包括C1、C2和Graal。
    6.Asmtools.jar下载地址https://ci.adoptopenjdk.net/view/Dependencies/job/asmtools/lastSuccessfulBuild/
    7.JVM将Boolean类型看作是int类型,true就是1,false就是0,flag如果改成2第二个判1等式就不成立,所以只有第一个判0等式通过。
    2018-12-30
    1
    15
  • ace
    最后awk那段分析了下。希望分析正确 也对大家有帮助
    1、NR==1,/iconst_1/ 是用于匹配行 匹配第一行到第一个出现iconst_1的行
    2、{}进行脚本执行。针对第一步中匹配的行执行内置的字符串函数sub 做替换
    3、1 都会被执行。在awk 1被计算为true,表现为默认操作 print $0 也就是打印整行
    整体效果是打印所以文本行,但第一个出现iconst_1的做替换。
    2018-08-05
    13
  • 陈树义
    asmtools.jar 是在哪里下载的,怎么在给的链接页面没找到。
    2018-07-21
    13
  • 志文
    Java 作为一门高级程序语言,它的语法非常复杂,抽象程度非常高,所以不能直接在硬件上执行。所以要引入JAVA虚拟机。
    我觉得理由不充分,JAVA为什么不能像c++一样直接转成机器码呢?从理论上是可以用编译器来实现这个的功能的。问题在于直接像c++那样编译成机器码,就实现不了跨平台了。那么是不是跨平台才是引入JAVA虚拟机的重要原因呢 。请老师解答
    2018-07-22
    1
    11
  • 踏雪无痕
    您好,我现在所在的项目经常堆外内存占用非常多,超过总内存的70%,请问一下有没有什么方法能观察一下堆外内存有什么内容?

    作者回复: 堆外内存的话,就把JVM当成普通进程来查找内存泄漏。可以看下Google Performance Tools相关资料

    2018-07-20
    10
  • 欲风
    方法区和元空间是一个概念吧,能不能统一说法到jdk8之后的版本~
    2018-07-20
    1
    9
  • kernel
    评论比文章精彩,学习到更多
    2018-08-13
    8
  • 那我懂你意思了
    老师,那个pc寄存器,本地方法栈,以及方法栈,java方法栈这三个组成的就是我们常统称的栈吧,然后也叫栈帧?

    作者回复: JVM里的栈指的应该是Java方法栈和本地方法栈。每个方法调用会在栈上划出一块作为栈帧(stack frame)。栈是由多个栈帧构成的,就好比电影是由一个个帧构成的。

    2018-07-20
    8
收起评论
99+
返回
顶部