[转帖]JVM 虚拟机(整体架构、类文件结构)我来了~~~

jvm,虚拟机,整体,架构,文件,结构 · 浏览次数 : 0

小编点评

**类文件结构** **类文件包含以下数据项:** * 类型名称(String) * 数量(int)描述(String) * 常量池(cp_info 结构) * 方法(method) * 属性(attribute) * 方法(method) **常量池** * 计数器(int) * 结构体(cp_info 结构) **结构描述** * **魔数与版本1**(字节) * **版本号**(int) * **常量池**(cp_info 结构) **其他信息** * **其他信息**(其他数据类型)

正文

JVM 虚拟机(整体架构、类文件结构)我来了~~~

 

 

虚拟机

1.1 发展历程

1.1.1 java 往事

​ Java 诞生在一群懒惰、急躁而傲慢的程序天才之中。

​ 1990 年 12 月,Sun 的工程师 Patrick Naughton 被当时糟糕的 Sun C++ 工具折磨的快疯了。他大声抱怨,并威胁要离开 Sun 转投当时在 Steve Jobs 领导之下的 NeXT 公司。领导层为了留住他,给他一个机会,启动了一个叫做 Stealth(秘密行动)的项目。

​ 随着 James Gosling 等人的加入,这个项目更名为 Green。其目标是使用 C++ 为嵌入式设备开发一种新的基础平台技术,James Gosling 本人负责开发一个编辑器。正如人们事后分析的那样,这位天才的程序员太懒惰,所以没有把 C++ 学好,开发中碰了一头包。于是他决定开发一种新的编程语言。他把这种语言命名为 C++++--,意思是 C++ “加上一些好东西,减去一些坏东西”。显然这个糟糕的名字不可能长久,于是很快这种颇受同伴喜爱的小语言被命名为 Oak。

​ 到了 1992 年 9 月,Oak 语言连同 Green OS 和一些应用程序一起发布在称做 Start 7 的小设备上,有了第一次精彩的亮相。随后,Sun 开了一家名为 FirstPerson 的公司,整个团队被转移到这家公司里研发机顶盒,以投标时代华纳公司的一个项目。这帮天才被技术狂热所鼓舞,开发出了一个高交互性的设备,结果没想到时代华纳公司和有线电视服务商并不愿意用户拥有那么大的控制权,从而在竞标之战中败给了 SGI。

​ Sun 无奈地关闭了 FirstPerson,召回了整个团队,java 的出路却没有因此而断送,随着互联网发展的涌动,java 开始离开嵌入式小设备,往互联网倾斜。1994 年,Oak 被命名为 Java,回到了激情澎湃的 IT 产业,抓住互联网的大潮,从此一发不可收拾。

​ 剩下的事情,大家都知道了……

1.1.2 版本迭代

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

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

  • 1996 年,JDK(Java 开发所使用的工具包)1.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 年,JDK5.0 发布,对语法易用性做了很大改进,新增了泛型、枚举等,代表技术有:并发包等。

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

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

  • 2011 年,JDK7 发布。

  • 2013 年,JDK8(LTS) 发布,函数式编程,lamda 表达式。

  • 2017 年,JDK9

  • 2018 年,JDK 10,11(LTS)正式发布

  • 2019 年,JDK 12,13

  • 2020 年,JDK 14,15

  • 2021 年,JDK 16,17(LTS)

附:sun与微软的轶事
java诞生的1995年,正是微软在软件产业地位达到巅峰的时代。但是这个初出茅庐的毛头小子硬是引起了微软帝国的关注。所以96年微软就向sun申请了java认证。
微软的加持确实推动了人们对java的信心和兴趣。
但是好景不长,从1997年发布Visual J++的第一个版本开始,微软就开始在Java中掺入自己的私有扩展。这毫无疑问引起Sun的高度重视。
1997年10月,Sun向美国加州地方法院起诉微软公司违反两公司就微软使用Java技术所签定的合同,指控微软公司在自己的Java产品中做了“不恰当的修改”,违反了合同中承诺向用户提供Java兼容产品的条款。
这一官司一直打到了2001年1月双方达成和解。
到了2001年7月,微软公布新版的Windows XP将不再支持Sun的JVM,并且推出了.NET平台与Java分庭抗礼。
当然目前.net用的人少了,这是后话。

 

1.1.3 两种 jdk

openjdk vs oraclejdk:

  1. Oracle JDK 将更多地关注稳定性,它重视更多的企业级用户,而 OpenJDK 经常发布以支持其他特性,不太稳定。
  2. Oracle JDK 支持长期发布的更改(LTS),而 Open JDK 仅支持计划和完成下一个发行版。
  3. Oracle JDK 根据二进制代码许可协议获得许可,而 OpenJDK 根据 GPL v2 许可获得许可。
  4. 2019 年 1 月之后发布的 Oracle Java SE 8 的公开更新将无法用于商业,但是,OpenJDK 是完全开源的,可以自由使用。
  5. Oracle JDK 的构建过程基于 OpenJDK,因此 OpenJDK 与 Oracle JDK 之间没有技术差异。
  6. 顶级公司正在使用 Oracle JDK,Open JDK 不太受欢迎。
  7. Oracle JDK 具有良好的 GC 选项和更好的渲染器,而 OpenJDK 具有更少的 GC 选项
  8. 在响应性和 JVM 性能方面,Oracle JDK 提供了更好的性能。
  9. Oracle JDK 在运行 JDK 时不会产生任何问题,而 OpenJDK 有时会产生一些问题。
  10. Oracle JDK 将从其 10.0.X 版本将收费,用户必须付费或必须依赖 OpenJDK 才能使用其免费版本。
  11. Oracle JDK 完全由 Oracle 公司开发,而 Open JDK 项目由 IBM,Apple,SAP AG,Redhat 等顶级公司加入和合作。

1.2 JVM 体系

 

  • JDK(Java Development Kit)是 Java 语言的软件开发工具包,也是整个 java 开发的核心,它包含了 JRE 和开发工具包

  • JRE(Java Runtime Environment),Java 运行环境,包含了 JVM 和 Java 的核心类库(Java API)

  • JVM(Java Virtual Machine),Java 虚拟机,它是运行在操作系统之上的,它与硬件没有直接的交互

所谓 “一次编码,随处运行 “正是基于不同系统下的 jvm 帮你掩盖了系统之间接口的差异:

 

总结

jdk 是开发人员的工具包,它包含了 java 的运行环境和虚拟机,而一次编写到处运行就是基于 jvm

1.3 各种虚拟机

1.3.1 清单

1、Sun Classic VM

​ 世界上第一款商用 Java 虚拟机。

1996 年随着 Java1.0 的发布而发布,JDK1.4 时完全被淘汰

2、BEA JRockit

专注于服务端应用,号称是世界上最快的JVM

​ 后来被 Oracle 收购;Oracle JRockit (原来的 Bea JRockit)

3、IBM 公司的 J9VM

全称:IBM Technology for Java Virtual Machine,简称 IT4J,内部代号:J9

是 IBM 自己开发的一款 JVM

市场定位于 HotSpot 接近,服务器端、桌面应用、嵌入式等多用途 VM

4、HotSpot VM(现在最常用)

​ 它是 Sun JDK 和 OpenJDK 中所带的虚拟机,也是目前使用范围最广的 Java 虚拟机。

5、其他

(TaobaoJVM 、Graal VM、Azul VM、Liquid VM、Apache Harmony、)虚拟机

1.3.2 查看

shawn@macpro:~ > java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
  • hotspot 虚拟机

  • Client VM 是专门为快速启动和小内存 (small footprints) 而优化的,像 GUI 就很适合

  • Server VM 是专门为高性能应用而优化的,如服务器应用

  • 版本是基于 tag 为 1.8.0_181

1.4 jvm 整体架构

1.4.1 java 运行过程

 

1. 源码编译:通过 Java 源码编译器将 Java 代码编译成 JVM 字节码(.class 文件)

2. 类加载:通过 ClassLoader 及其子类来完成 JVM 的类加载

3. 类执行:字节码被装入内存,进入 JVM 虚拟机,被解释器解释执行

1.4.2 jvm 模型

 

由上面的图可以看出,JVM 虚拟机中主要是由三部分构成,分别是类加载子系统、运行时数据区、执行引擎。

类加载子系统

Java 虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型。

运行时数据区

Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域。

这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而一直存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。

执行引擎

执行引擎用于执行 JVM 字节码指令,主要有两种方式,分别是解释执行和编译执行,区别在于,解释执行是在执行时翻译成虚拟机指令执行,而编译执行是在执行之前先进行编译再执行。

解释执行启动快,执行效率低。编译执行,启动慢,执行效率高。

垃圾回收器就是自动管理运行数据区的内存,将无用的内存占用进行清除,释放内存资源。

本地方法库、本地库接口

在 jdk 的底层中,有一些实现是需要调用本地方法完成的(使用 c 或 c++ 写的方法),就是通过本地库接口调用完成的。比如:System.currentTimeMillis () 方法。

2、类文件结构

了解 jvm 后续的一切动作,先从字节码开始。它是一切发生的源头。

2.1 测试案例

2.1.1 源代码

package com.itheima.jvm.demo;

public class ClassStruct {

    private static String name = "JVM";

    public static void main(String[] args) {
        System.out.println("Hello " + name);
    }

}

2.1.2 编译

1)maven 定义编译的版本

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

2)编译

mvn clean compile

2.2 字节码结构

2.2.1 二进制概览

1)vscode 打开

 

2)class 文件是一个二进制文件,转化后是 16 进制展示,实际上 class 文件就是一张表,它由以下数据项构成,这些数据项从头到尾严格按照以下顺序排列:

类型名称数量描述
u4 magic 1 魔数
u2 minor_version 1 次版本号
u2 major_version 1 主版本号
u2 constant_pool_count 1 常量个数
cp_info constant_pool constant_pool_count - 1 具体常量
u2 access_flags 1 访问标志
u2 this_class 1 类索引
u2 super_class 1 父类索引
u2 interfaces_count 1 接口索引
u2 interfaces interfaces_count 具体接口
u2 fields_count 1 字段个数
field_info fields fields_count 具体字段
u2 methods_count 1 方法个数
method_info methods methods_count 具体方法
u2 attributes_count 1 属性个数
attribute_info attributes attributes_count 具体属性

3)图示如下:

 

2.2.2 魔数与版本

1)魔数:

CAFEBABE,咖啡宝宝,固定的。

 

2)版本号:

34,换成 10 进制就是 52

 

jdk 的版本标记映射关系:

 

说明编译用的是 jdk8,我们改成 1.6,重新执行 mvn clean compile ,再来查看 class 文件试试:

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

扩展

在开发中,经常会遇到类似 Unsupported major.minor version 51.0 的错误,一般情况下都是 JDK 版本不匹配造成的。 虽然 jdk 代码在执行时基本上向下兼容,但是!开发环境和服务器环境 jdk 最好一致,不要尝试这个坑。

区分和理解两个环境:编译环境,运行环境

2.2.3 常量池

再往下遵从相同的规律: 计数器(标注后面有多少个) + 对应个数的结构体

我们以常量池为例:

1)位置

 

2)结构说明

常量池记录了 jvm 内的一堆常量信息,这部分由 【2 个字节计数】 + 【n 个 cp_info 结构】组成

 

其中 cp_info 有多种类型:

  • 直接类型,存的就是当前值,这种像 Integer,Long 等长度都是确定的
  • 引用类型,存的是指向其他位置的指针

附:绿色代表指针,橙色代表直接类型

3)案例

下面以 String 为例,String 是一种引用类,它会指向一个 utf8 类型来存储真实的信息

jdk 提供了一个工具,javap,可以查看常量列表的详细内容:

javap -v ClassStruct.class

 

2.2.4 其他信息

1)说明

常量池之后,是紧挨的一系列信息,这些信息大同小异,无非就是值、或者引用

(参考上面 2.3.3 里的表格和图例)

  • 访问标记:public abstract 等信息
  • 类索引,class 类型,最终指向一个 utf8,标记当前类的名字
  • 父类,同上
  • 接口,2 字节记录数量,后面记录多个接口类型
  • 接下来是字段、方法、属性,都是 2 字节记录后面多少个,后面紧跟对应的结构体类型

2)注意事项

要看懂 javap 后的格式,明白这些格式,可以轻松看懂 class 结构

| 类型 | 标识符 | 案例 | 说明 | | -------- | ------------ | ------------------ | ---------- | | 数组 | [ | [Ljava.lang.String | String 数组 | | 对象 | L | Lcom.test.Demo | | | 基本类型 | 大写字母开头 | B=byte,I=int…… | | | | | | |

组合类型

类型案例说明
类里的属性、字段、方法等 com.test.Demo.name:Ljava.lang.String 英文点号隔开
标识什么类型 com.test.Demo.getName:()Ljava.lang.String 英文冒号隔开
方法 (参数类型) 返回值类型 英文括弧,后面是返回值类型

3)实例分析

 

本文由传智教育博学谷教研团队发布。

如果本文对您有帮助,欢迎关注点赞;如果您有任何建议也可留言评论私信,您的支持是我坚持创作的动力。

转载请注明出处!

与[转帖]JVM 虚拟机(整体架构、类文件结构)我来了~~~相似的内容:

[转帖]JVM 虚拟机(整体架构、类文件结构)我来了~~~

JVM 虚拟机(整体架构、类文件结构)我来了~~~ 虚拟机 1.1 发展历程 1.1.1 java 往事 ​ Java 诞生在一群懒惰、急躁而傲慢的程序天才之中。 ​ 1990 年 12 月,Sun 的工程师 Patrick Naughton 被当时糟糕的 Sun C++ 工具折磨的快疯了。他大声抱

[转帖]JVM(3)之垃圾回收(GC垃圾收集器+垃圾回收算法+安全点+记忆集与卡表+并发可达性分析......)

《深入理解java虚拟机》+宋红康老师+阳哥大厂面试题2总结整理 一、堆的结构组成 堆位于运行时数据区中是线程共享的。一个进程对应一个jvm实例。一个jvm实例对应一个运行时数据区。一个运行时数据区有一个堆空间。 java堆区在jvm启动的时候就被创建了,其空间大小也就被确定了(堆是jvm管理的最大

[转帖]【JVM】字节码执行引擎

引入 class文件就是字节码文件,是由虚拟机执行的文件。也就是java语言和C & C++语言的区别就是,整个编译执行过程多了一个虚拟机这一步。这个在 类文件结构 中已经解释。上一节讲了虚拟机是如何加载一个class的,这一节就讲解虚拟机是如何执行class文件的。 运行时栈帧结构 1.定义 栈是

[转帖]【JVM】常用虚拟机参数及实例

常用参数表 参数描述-XX:+PrintGC启动java虚拟机后,只要遇到gc,就打印日志-XX:+PrintGCDetailsgc发生时,打印更详细的日志-XX:+PrintHeapAtGC每一次GC后,都打印堆信息-XX:+PrintGCTimeStampsgc发生时,额外打印gc时间,该时间为

[转帖]常用JVM虚拟机参数说明

常用JVM虚拟机参数说明 原文地址:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html 非标准选项 参数说明-Xcomp强制JVM虚拟机在方法第一次被调用的时候就进行本地编译。-Xint强制JVM运行在解释模式。在

[转帖]12.JVM运行时数据区之虚拟机栈概述

`https://blog.csdn.net/u011069294/article/details/107050001` 目录 1. 内存中的栈与堆2.栈的优点 1. 内存中的栈与堆 栈是运行时单位,堆是存储的单位。 栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。 堆解决的是数据存储的问

[转帖]JVM类加载机制

概述 虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Cl

[转帖]【JVM】JVM概述

1.JVM定义 JVM 是Java Virtual Machine(JVM )的缩写,Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令进行执行,这样实现了Java“一次编译,到处运行”。 2.JVM组成 JVM由三大部分组成:类加载器(ClassLoader subsystem),执

【转帖】JVM的发展历程

目录 1.Sun Classic VM2.Exact VM3.Sun HotSpot(主流)4.JRockit5.IBM J96.下一代虚拟机Graal VM 1.Sun Classic VM 2.Exact VM 3.Sun HotSpot(主流) 通常所说的JVM都是指的HotSpot。 4.J

[转帖]JVM系列之:你知道Java有多少种内存溢出吗

本文为《深入学习 JVM 系列》第二十五篇文章 Java内存区域 关于这部分内容大多来源于《深入理解Java虚拟机》一书。 Java 运行时数据区域(JDK8)如下图所示: 关于上述提到的线程共享和线程隔离区域,下图做详细讲解: 程序计数器 程序计数器是一块较小的内存空间,可以看作是当前线程所执行的