草庐IT

JVM虚拟机我来了~~~

博学谷狂野架构师 2023-04-16 原文

虚拟机

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虚拟机我来了~~~的更多相关文章

  1. 在VMware16虚拟机安装Ubuntu详细教程 - 2

    在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主

  2. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  3. ruby-on-rails - Rails 验证虚拟属性 - 2

    我这个模型:classBunny每当我提交一个表单来创建这个模型时,我都会收到以下错误:#的未定义方法“number_before_type_cast” 最佳答案 我通过将此方法添加到我的Bunny模型中解决了这个问题:defnumber_before_type_castnumberend我不喜欢它,但我想在有人发布更好的解决方案之前它会起作用。 关于ruby-on-rails-Rails验证虚拟属性,我们在StackOverflow上找到一个类似的问题: h

  4. 【云计算】私有云在VMware下虚拟机的创建与配置(图文教程) - 2

    【适用平台】私有云   说明:完成私有云部分是需要两台虚拟机的,分别为controller、compute两个节点,但我们只需配置一台,然后克隆就方便多啦!需要用到的映射文件:关于vm的安装我就不介绍的,毕竟挺简单的,下面让我们看看基于私有云模块中,虚拟机的搭建吧。1、创建新的虚拟机,这里一般我会选择自定义,毕竟后面的配置都要根据私有云相关来进行搭建,会比较复杂。(如果是基础的可以选择典型,典型的满足一般虚拟机的配置) 2、选择稍后安装操作系统会比较方便后续的选择,这里你也可以自己选择自己的映像文件(但不建议)  3、我们是基于Linux下操作的,所以选择Linux客户机操作系统,版本选择自己

  5. 续集来了丨UI自动化测试(二):带视频,实在RPA高效进行web项目UI自动化测试 - 2

    一、什么是web项目ui自动化测试?通过测试工具模拟人为操控浏览器,使软件按照测试人员的预定计划自动执行测试的一种方式,可以完成许多手工测试无法完成或者不易实现的繁琐工作。正确使用自动化测试,可以更全面的对软件进行测试,从而提高软件质量进而缩短迭代周期。二、构建测试用例的“九部曲”(一)创建流程包划分功能模块日常测试活动中,都会根据功能模块进行拆分,所以在设计器中我们可以通过创建流程包的方式来拆分需要测试的功能模块,如下图中操作创建一个电脑流程包并且取名为对应的功能模块名称,如果有多个功能模块就创建多个对应的流程包,实在RPA设计器有易用的图形可视化界面,方便管理较多的功能模块。(二)在流程包

  6. VMware虚拟机与本地主机进行磁盘共享(详解) - 2

    VMware虚拟机与本地主机进行磁盘共享前提虚拟机版本为Windows10(专业版,不是可能有问题)本地主机为家庭版或学生版(此版本会有问题,但有替代方式)最好是专业版VMware操作1.关闭防火墙,全部关闭。2.打开电脑属性3.点击共享-》高级共享-》权限4.如果没有everyone,就添加权限选择完全控制,然后应用确定。5.打开cmd输入lusrmgr.msc(只有专业版可以打开)如果不是专业版,可以跳过这一步。点击用户-》administrator密码要复杂密码,否则不行。推荐admaiN@1234类型的密码。设置完密码,点击属性,将禁用解开。6.如果虚拟机的windows不是专业版,可

  7. 虚拟机上进行java项目部署 - 2

    🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀虚拟机上进行java项目部署,自己的一点总结,一起学习,一起进步,一起成长!🛸🛸🛸🛸🛸🛸🛸🛸🛸🛸目录文章目录虚拟机上进行java项目部署1.JDK安装2.TOMCAT安装3.DOCKER1、YUM安装2、docker部署java4、最后 【yzh2022.9】1.JDK安装1、我们安装VM的时候,使用命令java-version查看 java-version这里显示JDK的信息是openjdkversion"1.8.0_262",我们会发现这个JDK是VM自带的当然你也可以通过命令rpm-qa|grepjava来查看相关的java信息 rpm-qa|grepjava【如果不

  8. 【操作系统实验】Ubuntu Linux 虚拟机用户管理 - 2

    文章目录一、用户二、用户分类1、普通用户2、超级用户3、系统用户三、用户相关文件1、/etc/passwd文件2、/etc/shadow文件四、用户管理命令1、useradd2、adduser3、passwd4、usermod5、userdel一、用户Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户都必须先向系统管理员申请一个账号,然后以这个账号的身份进入系统。在Linux系统中,任何文件都属于某一特定用户,而任何用户都隶属于至少一个用户组。用户名(username):每个用户账号都拥有一个惟一的用户名和各自的口令。用户在登录时键入正确的用户名和口令后,就能够进入系

  9. Conda虚拟环境的复制和迁移 - 2

    Conda虚拟环境的复制和迁移在本机复制Conda虚拟环境condacreate--namesnapshot--clonemyenv相同操作系统之间复制环境方法一:requirements.txt这个方法不推荐,因为只会导出你使用pip安装的依赖包,不会导出虚拟环境所依赖的包,并不适用于虚拟环境的迁移的应用场景。事实上,此方法比较适用于,已经明确知道依赖哪些包,我们只需要package信息的情况,如写项目文档,告诉别人运行我这个系统必须安装哪些依赖包。而忽略虚拟环境本身的依赖环境。pipfreeze>requirements.txt#生成requirements.txtpipinstall-r

  10. ruby - 是否可以在 Vagrant 完成所有配置后在虚拟机上运行脚本? - 2

    我正在使用Vagrantv1.5.1创建虚拟机(VM)集群。在供应了所有VM之后,是否可以在其中一台机器上运行单个脚本?我要运行的脚本将设置从一个VM到所有其他VM的无密码SSH。例如我在Vagrant(CentOS6.5)中配置的节点如下。节点1节点2节点3节点4我的Vagrantfile如下所示。(1..4).eachdo|i|config.vm.define"node-#{i}"do|node|node.vm.box="centos65"...omitted..endend完成所有这些后,我需要在node1上运行一个脚本,以启用到node2、node3和node4的无密码SSH。

随机推荐