当前位置:网站首页 > Java基础 > 正文

java虚拟机需要什么基础



该文章属于Java进阶部分的JVM入门,本章讲述了JVM的历史、Java源代码到机器码的过程以及 Class字节码文件的内部结构等。
了解了这篇文章,能让你深入地了解JVM知识,保证在短时间内掌握JVM!

JVM 入门教程(上篇)

开篇:为什么要学虚拟机

  1. 学习Java虚拟机能深入地理解Java这门语言

  2. 学习虚拟机是为了线上排查问题打下基础

  • 学会垃圾回收机制等,看懂Java虚拟机内存模型,看懂GC日志,解决线上的Java应用崩溃问题

第 1 讲 Java语言的前世今生

1. JDK 与 JRE

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

  • JDK 除了包含JRE外,还附带了一系列开发、诊断工具。

  • 一般来说,如果只需要运行Java程序,那么安装JRE即可。但如果要运行Java程序的开发,那么就需要安装JDK。

2. JDK 与 J2SE

  • Java SE 是Java三大技术体系的一个。

  • 在1998年,JDK1.2发布,Java技术体系被拆分为 J2SE、J2EE、J2ME三大体系。

  • J2SE称之为标准版技术体系,它包含了构成Java语言核心的类,如:数据库连接、网络编程、接口定义等。J2SE技术体系主要用于桌面应用软件的编程。

  • J2EE称之为企业版技术体系,它除了包含J2SE中的类,还包含用于开发企业级应用的类,如:Servle、JSP、EJB等。J2EE技术体系主要用于分布式的网络程序的开发,如电子商务网站等。

  • J2ME称之为嵌入式技术体系,它包含J2SE中的一部分类。J2ME技术体系主要用于消费电子产品的软件开发,如:手机、PDA、寻呼机等。

3. J2SE 与 Java SE

  • J2SE 与 Java SE ,其实它们指的是同一个东西,只不过在2006年JDK 1.6 发布时,讲J2SE、J2EE、J2ME的命名方式改为 Java SE 6、Java EE 6、Java ME 6。

4. Java语言的历史

  • 在 1991 年,James Gosling 博士发布了 Oak,这个是 Java 语言的前身。但一直到 1995 年的时候,Oak 语言才改名为 Java。

  • 1991 年,James Gosling 博士发布产品 Oak,这是 Java 语言的前身。

  • 1995 年,Oak 语言改名为 Java。

  • 1996 年,JDK1.0 发布,提供了纯解释执行的 Java 虚拟机实现:Sun Classic VM。

  • 1997 年,JDK1.1 发布,代表技术有:JDBC、JavaBeans、内部类、反射。

  • 1998 年,JDK1.2 发布,Java 技术体系被拆分为 J2SE、J2EE、J2ME 三大体系。

  • 2000 年,JDK1.3 发布,默认的 Java 虚拟机由 Sun Classic VM 改为 HotSopt。

  • 2002 年,JDK1.4 发布,Java 真正走向成熟,代表技术有:正则表达式、NIO等。

  • 2004 年,JDK1.5 发布,对语法易用性做了很大改进,新增了泛型、枚举等,代表技术有:并发包等。

  • 2006 年,JDK1.6 发布,将 J2EE/J2SE/J2ME 的命名方式改为 Java SE 6、Java EE 6、Java ME 6。

  • 2009 年,Sun 公司因为经营不善被 Oracle 公司收购。

  • 2011 年,JDK1.7 发布。

  • 2013 年,JDK1.8 发布。

  • …………

5. 总结

  • 这一部分简单地介绍了一些常见概念上地区别,以及Java语言的历史,让大家对Java语言的发展有一个大致的理解。

第 2 讲 Java虚拟机的历史

1. Sun Classic —— 虚拟机始祖

  • 在 1996 年 1 月 23 日,Sun 发布 JDK1.0,齐总自带的虚拟机就是Classic VM。但是这款虚拟机有个特点,只能使用纯解释器的方式来执行Java代码,此时解释器与编译器无法共同存在。到JDK1.4正式退出历史舞台。

2. Sun Exact VM —— 无疾而终

  • 在 JDK1.2 时发布了Exact VM 的虚拟机,尝试解决 Classic VM遇到的所有问题,它的执行系统解决了Classic VM 存在的编译器和解释器无法同时工作的问题,还具备了一些现代高性能处理器的特性,如:两级即时编译等。

  • Exact VM 还改进了虚拟机的对象查找方式,使用了准确式内存管理,即虚拟机可以知道内存中某个位置的数据具体是什么类型,这样就减少了查找的开销,提升了执行性能。

  • 但可惜的是,虽然Exact VM发布了ÿjava虚拟机需要什么基础0c;但是直到它退出时,都没有被大规模使用过。

3. Sun HotSpot VM —— 武林盟主

  • HotSpot不仅仅有前面说到两款虚拟机的优点,也有许多自己的新技术,如:热点探测技术。热点探测技术指的是通过执行计数器找出最具优化价值的代码,然后通知JIT编译器一方法为单位进行深度优化编译。

  • 从 2000 年JDK1.3发布,HotSpot VM作为默认的虚拟机开始登上历史舞台。

4. BEA JRockit / IBM J9 VM —— 百家争鸣

  • 前面说的都是 Sun 公司推出的虚拟机,其他组织、公司也研发过不少的虚拟机实现。这里是最著名的。

  • BEA 公司的 JRockit 是一款专注于服务器硬件和服务端应用场景的虚拟机,其针对服务端场景做了大量的优化,因此其不太关注程序启动速度。JRockit 虚拟机内部不包含解释器实现,全部代码都靠即时编译器编译后执行。此外,其提供的 MissionControl 服务套件也十分强大。

  • IBM 公司的 J9 VM 则是一款比较通用的虚拟机,其定位应用于从服务端到桌面应用再到嵌入式的多用途虚拟机。IBM 公司开发 J9 VM 的目的是将其作为 IBM 公司各种 Java 产品的执行平台。

5. 那些无名虚拟机 —— 武林外传

  • 除了上述的这些虚拟机之外,其实还有各种各样的虚拟机存在。

  • 例如性能最强悍的并不是上面所说的虚拟机,而是名为 Azul VM 和 BEA Liquid VM 的专用商业及虚拟机。这些虚拟机只运行在特定硬件平台,因此要求比较高。但其性能也是非常强悍的。其可以管理至少数十个 CPU 和数百 GB 的内存资源,还提供在巨大内存范围内实现可控 GC 时间的垃圾收集器等等。

  • 此外还有许许多多其他的虚拟机存在,例如:Apache Harmony、Google Android Dalvik VM、Mircosoft JVM 等等。

  • Oracle 看了这么些历史,似乎都是在说 Sun公司发布的虚拟机,与 Oracle 似乎没有什么关系。但在 2010 年,Oracle 公司收购了 Sun 公司,这样 Oracle 就拥有了 HotSpot VM。再加上其在 2008 年收购 BEA 公司获得的 JRocket VM,Oracle 公司就拥有了地球上最优秀的两款虚拟机。

  • 对于虚拟机未来的规划,Oracle 宣布会将 JRockit 的优秀特性整合到 HotSpot VM 中,例如移植 JRockit 的垃圾回收器和 MissionControl 服务。

第 3 讲 到底什么是虚拟机?

  • 为什么不同系统上的软件无法安装,这是因为操作系统底层的实现是不一样的。对于Windows系统来说,exe后缀的软件代码最终编译成Windows系统能识别的机器码。而Mac OSX 系统来说,dmg后缀的软件代码最终编译成 Mac OSX 系统能识别的代码。

  • 与其他语言不同,Java语言并不直接讲代码编译成与系统有关的机器码,而是编译成一种特定的语言规范,这种语言规范我们称之为字节码。无论Java程序要在Windows系统,还是Mac OSX系统,或者是Linux系统,它首先都得编译成字节码文件,之后才能运行。

  • 但即使编译成字节码文件了,各个系统还是无法明白字节码文件的内容,这时就需要Java虚拟机的帮助了。Java虚拟机会解析字节码文件的内容,并将其翻译为各操作系统能理解的机器码。

  • Java虚拟机运行的是字节码文件,如果你用php语言写一段代码,并自己用特定编译器能生成符合字节码规范的字节码文件,那么Java虚拟机也是可以运行的。

  • 简单来说Java虚拟机就是一个字节码翻译器,它将字节码文件翻译成各个系统对应的机器码,确保字节码文件能在各个系统正确运行。

第 4 讲 对于Java语言,从源代码到机器码,发生了什么?

编译器可以分为:前端编译器、JIT编译器和AOT编译器

前端编译器

前端编译器:源代码到字节码 对于Java虚拟机来说,其实际输入的是字节码文件,而不是Java文件。 怎样讲Java代码转化为字节码文件?我们知道在JDK的安装目录里有一个javac工具,就是它讲Java代码翻译成字节码,这个工具我们叫做编译器,因为是处于编译前期,所以被称为前端编译器。常见的前端编译器有Sun的javac,Eclipse JDT的增量编译器(ECJ)。 通过javac编译器,我们可以很方便地将java源文件翻译成字节码文件。javac编译器解析Java源码,并生成字节码文件地过程,就是使用javac编译器把Java语言规范转化为字节码语言规范。

javac编译器地处理过程可以分为下面地四个阶段:

第一阶段:词法、语法分析

javac编译器会对源代码地字符进行一次扫描,最终生成一个抽象地语法树。

第二阶段:填充符号表

对抽象地类或接口进行符号填充,等到类加载阶段,javac编译器会将符号替换成具体地内存地址。

第三个阶段:注解处理

Java是支持注解地,因此在这个阶段会对注解进行分析,根据注解地作用将其还原成具体的指令集。

第四个阶段:分析与字节码生成

javac编译器会根据上面几个阶段分析出来的结果,进行字节码的生成,最终输出为class文件。

JIT编译器(即时编译器)

  • JIT编译器:从字节码到机器码

  • 当源代码转化为字节码后,其实要运行程序有两种选择:

    • 一种是Java解释器解释执行字节码,另一种则是使用JIT编译器将字节码转化为本地机器代码。

    • 两者区别在于,前者启动速度快但运行速度慢,后者启动速度慢但运行速度快。

  • 在HotSpot虚拟机内置了两个即时编译器,分别为Client Compiler和Server Compiler。

  • 这两种不同的编译器衍生出两种不同的编译模式,我们分别称之为:C1编译模式、C2编译模式(非官方说法)。

C1编译模式和C2编译模式的区别

  • C1编译模式会将字节码编译为本地代码,进行简单、可靠的优化,如:有必要将加入性能监控的逻辑。优化相对比较保守,比C2较快。

  • 而C2编译模式,也是将字节码编译为本地代码,但是会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。C2的编译质量相对较好,但耗时更长。

对于HotSpot虚拟机有三种运行模式可选

  1. 混合模式:

  • C1和C2两种模式混合起来使用,这是默认的运行模式,如果想单独使用C1模式或C2模式,使用 -client 或 -server 打开即可。

  1. 解释模式:

  • 所有代码都解释执行,使用 -Xint 参数可以打开这个模式。

  1. 编译模式:

  • 此模式优先采用编译,但是无法编译时也会解释执行,使用 -Xcomp 打开这种模式。

此时,我们了解了从Java源代码到字节码,再从字节码到机器码的全过程,可以到这里就结束了。但是Java中还有一个AOT编译器,它能直接将源代码转换为机器码。

AOT编译器

  • AOT编译器:源代码到机器码

  • AOT编译器的基本思想是:在程序执行前生成Java方法的本地代码,以便在程序运行时直接使用本地代码,也就是在进入JVM之前就已经将本地机器码生成了。

  • 优点:
    • 启动速度快,减少运行时的开销

  • 限制:
    • 由于缺乏运行时信息,AOT编译质量也就是优化效果通常不如JIT编译。

    • Java的动态类加载等特性可能会增加AOT编译的复杂性。

总结

  • 在JVM中有三个非常重要的编译器,它们分别是:前端编译器、JIT编译器、AOT编译器。

  • 前端编译器,最常见的是javac编译器,将Java源代码编译为Java字节码文件。

  • JIT编译器(即时编译器),最常见的是HotSpot虚拟机中的Client Compiler和 Server Compiler,将Java字节码编译成本地机器代码。

  • AOT编译器能将源代码直接编译为本地机器码。

编译速度和编译质量上的区别

  • 编译速度上,解释执行>AOT编译器>JIT编译器

  • 编译质量上,JIT编译器>AOT编译器>解释执行。

而在JVM中,通过这几种不同方式的配合,使得JVM的编译质量和运行速度达到最优的状态。

第 5 讲 字节码文件结构

《Java虚拟机规范》规定了Java虚拟机结构、Class类文件结构、字节码指令等内容。
字节码文件结构是一组以8位字节为基础的二进制流,各数据项目严格按照顺序紧凑地排列在Class文件之中,中间没有添加任何分隔符。
在字节码结构中,有两种最基本的数据类型来表示字节码文件格式,分别是:无符号数和表。

无符号数
  • 无符号数属于最基本的数据类型。它以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节、8个字节的无符号数。

  • 无符号数可以用来描述数字、索引引用、数量或者按照UTF-8编码构成的字符串值。

  • 表是由多个无符号数或者其他表作为数据项构成的复合数据类型。

一个Class字节码文件的格式内容

  1. magic: 魔数,固定为0xCAFEBABE,用于标识这是一个Java Class文件。

  2. minor_versionmajor_version: 分别表示Class文件的次版本号和主版本号。

  3. constant_pool_count: 常量池中常量的数量。

  4. constant_pool: 常量池,存储了类中用到的所有常量,包括字符串、类名、方法名等。这里除了基本类型和UTF-8的字符串存储的是值外,其他的都是存储的索引。

  5. access_flags: 访问标志,标识类或接口的访问权限和属性(如public, final, abstract等)。 如:这个Class是类还是接口、是否定义位public类型、是否定义为abstract类型等。标志值可以通过相加来叠加。

  6. this_class: 当前类的索引,确定这个类的全限定名,指向常量池中的一个项。

  7. super_class: 父类的索引,确定这个类的父类的全限定名,指向常量池中的一个项。

  8. interfaces_countinterfaces: 接口的数量和接口列表。Class文件中由this_class、super_class、interfaces_count这三项数据来确定这个类的继承关系。

  9. fields_countfields: 字段的数量和字段列表。

  10. methods_countmethods: 方法的数量和方法列表。

  11. 上一篇: java语言基础类库
  12. 下一篇: java web程序开发基础

版权声明


相关文章:

  • java语言基础类库2024-10-15 20:10:01
  • java零基础入口设置2024-10-15 20:10:01
  • java基础数据和集合面试题2024-10-15 20:10:01
  • java入门零基础青鸟2024-10-15 20:10:01
  • java中国语言基础2024-10-15 20:10:01
  • java web程序开发基础2024-10-15 20:10:01
  • java0基础到贪吃蛇2024-10-15 20:10:01
  • java基础知识和技巧2024-10-15 20:10:01
  • java 的基础类型的整型2024-10-15 20:10:01
  • java程序基础复习题2024-10-15 20:10:01