Java虚拟机1:开篇-认识JVM

2018-07-06  本文已影响0人  叨唧唧的

1.前言

由于后期学习需要用到大量的JVM底层的东西,所有本人调整了一下学习计划,打算先从JVM入手,了解整个JAVA的运行机制,内存模型,编译原理等等一些底层的东西,这样在学习 后面的东西,会有一种豁然开朗的感觉。后期的内容有从网上直接复制粘贴的内容,但是大部分的内容都是经过自己整理后的,我觉得参照别人写的东西,未尝不可。如果是转载的文章,最后我列出转载的地址。虽然我做不了技术的创造者,但是争取做一个好的传播者。

2.什么是Java

经过了多年的发展,Java早已由一门单纯的计算机编程语言,演变为了一套强大的技术体系。是的,什么是Java,我想技术体系四个字应该是最好的概括了吧。Java设计者们将Java划分为3种结构独立但却彼此依赖的技术体系分支,它们分别对应着不同的规范集合和组件:

1、Java SE(标准版),主要活跃在桌面领域,主要包含了Java API组件。

2、Java EE(企业版),活跃在企业级领域,除了包含Java API组件外,还扩充有Web组件、事务组件、分布式组件、EJB组件、消息组件等,综合这些技术,开发人员完全可以构建出一个具备高性能、结构严谨的企业级应用,并且Java EE也是用于构建SOA(面向服务架构)的首选平台。

3、Java ME(精简版),活跃在嵌入式领域,称之为精简版的原因是,它仅保留了Java API中的部分组件,以及适应设备的一些特有组件。

上面讲到Java技术体系的分支,那既然Java是一种技术体系,我们来看一下组成这种技术体系的技术:

1、Java编程语言

2、字节码

3、Java API,包括Java API类库和来自商业机构以及开源社区的第三方类库

4、Java虚拟机

很多时候我们只关注了第一点,因为第一点才是和工作切实相关的。Java技术体系所包含的内容实际上Java官方有提供给我们一张图.

image

3.Java的优点

Java能获得如此广泛的认可,除了它拥有一门结构严谨、面向对象的编程语言之外,还有许多不可忽视的优点:

1、它摆脱了硬件平台的束缚,实现了“一次编写、到处运行”

2、它提供了一个相对安全的内存管理和访问机制,避免了绝大部分的内存泄露和指针越界问题

3、它实现了热点代码检测和运行时编译及优化,这使得Java应用能随着运行时间的增加而获得更高的性能

4、它有一套完整的应用程序接口,还有无数来自商业机构和开源社区的第三方类库来帮助它实现各种各样的功能

5、它与身俱来对分布式技术的支持就比较完善

但是,Java最大的优势和财富还不是以上这些,就像高翔龙老师在《Java虚拟机精讲》中写的,Java真正强大的地方是因为拥有全世界最多的技术拥护者和开源社区支持,他们无时无刻都保持着最充沛的体力与思维,一步一步地驱动着Java技术的走向。

4.JDK和JRE

两个常见的重要概念。其实上面的图中已经划分出了JDK和JRE的范围了。我们对这张图做一个归纳,用我们的语言简单地总结一下什么是JDK和JRE:

1、JRE(Java Runtime Enviroment),是支持Java程序运行的标准环境,包含:java虚拟机、JAVA SE API、运行java应用程序所必须的文件等。

2、JDK(Java Development Kit),是用于支持Java程序开发的最小环境,包含:JRE的部分,以及编译器和调试器等。

总结:

  1. 如果只是要运行JAVA程序,只需要JRE就可以。 JRE通常非常小,也包含了JVM。

  2. 如果要开发JAVA程序,就需要安装JDK。

OpenJDK

前面有讲过,“Java真正强大的地方是因为拥有全世界最多的技术拥护者和开源社区支持,他们无时无刻都保持着最充沛的体力与思维,一步一步地驱动着Java技术的走向”。其实JDK在一开始并不是开源的,但是随着开源运动的蓬勃发展,2006年Sun公司宣布将对Java开放源代码,开源的Java平台开发主要集中在OpenJDK项目上。2009年4月15日,Sun公司正式发布OpenJDK,JDK 7则是Java开源后发布的第一个版本,任何组织和个人都可以为Java的发展做出贡献。当然OpenJDK和真正的Oracle JDK(因为Sun公司被Oracle公司在2010年收购了嘛,所以就叫做Oracle JDK了)还是有区别的:

OpenJDK中的代码基本上都来自于Oracle JDK,属于Oracle JDK的一个分支,但是其中去除了一些非开源的组件和代码,替换成了开源的组件和代码,主要是加密和图形的部分。因此用OpenJDK代替Oracle JDK可能会有一些的不兼容。

对于OpenJDK感兴趣的,可以在OpenJDK官网http://download.java.net/openjdk/jdk7/下载OpenJDK的源代码。像Java虚拟机HotSpot、Java编译器Javac、JNI等等,源代码都在里面。

5.Java虚拟机(JVM)

5.1 概述

JVM是JRE的一部分,实际上它是一个虚构出来的小型计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。JAVA语言最大的特点就是跨平台运行,即所谓的“一次编写,处处运行”,它屏蔽了与具体操作系统平台相关的信息,类似一个程序代码和操作系统之间的一个中间件。

Java程序的跨平台特性主要是指字节码文件可以在任何具有Java虚拟机的计算机或者电子设备上运行,Java虚拟机中的Java解释器负责将字节码文件解释成为特定的机器码进行运行。因此在运行时,Java源程序需要通过编译器编译成为.class文件。众所周知java.exe是java class文件的执行程序,但实际上java.exe程序只是一个执行的外壳,它会装载jvm.dll(windows下,下皆以windows平台为例,linux下和solaris下其实类似,为:libjvm.so),这个动态连接库才是java虚拟机的实际操作处理所在。

5.2 JVM的主要功能

下面我们先看一张图,来了解JVM的主要功能和运行流程,如果看不懂没关系,后期的文章会系列的讨论。

image

三项主要功能:

5.3 加载

5.3.1 类加载的过程

下面简单介绍一下类加载的过程,类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。它们开始的顺序如下图所示:

[图片上传失败...(image-1617ab-1530860129287)]

其中**类加载的过程包括了加载、验证、准备、解析、初始化五个阶段**。其中验证,准备,解析又可以合在一起。

所以也可以分为三个大的步骤:装载(Load),链接(Link)和初始化(Initialize)链接又分为三个步骤,如下图所示:

[图片上传失败...(image-992da7-1530860129287)]

1) 装载:查找并加载类的二进制数据;

2) 链接

验证:确保被加载类的正确性,就是确保.class字节码符合虚拟机的要求;

准备:为类的静态变量分配内存,并将其初始化为默认值,这些变量所使用的内存都将在方法区中分配

解析:虚拟机将常量池内的符号引用替换为直接引用的过程;

3)初始化:初始化过程是一个执行类构造器<clinit>()方法的过程,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。其实就是执行类构造器方法的内容,包括给static变量赋予用户指定的值以及执行静态代码块

注意:

在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。

这里简要说明下Java中的绑定:绑定指的是把一个方法的调用与方法所在的类(方法主体)关联起来,对java来说,绑定分为静态绑定和动态绑定: 

5.3.2 类加载器

(1): 类加载器的结构

说到加载,不得不提到类加载器,下面就具体讲述下类加载器。下面看一张图了解一下类加载器的层次结构。

image

下面是类加载器的执行的各自不同的目录下的 .jar 包:

image

看上图我们知道类加载器有以下几类:

(2):类加载器的双亲委托模型

 上面层次关系称为类加载器的**双亲委派模型**。我们把每一层上面的类加载器叫做当前层类加载器的父加载器,当然,它们之间的父子关系并不是通过继承关系来实现的,而是**使用组合关系**来复用父加载器中的代码。该模型在JDK1.2期间被引入并广泛应用于之后几乎所有的Java程序中,但它并不是一个强制性的约束模型,而是Java设计者们推荐给开发者的一种类的加载器实现方式。

**双亲委派模型的工作流程是**:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委托给父类加载器去完成,依次向上,层层递进,最终所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。

优点:

使用双亲委派模型来组织类加载器之间的关系,有一个很明显的好处,就是Java类随着它的类加载器(说白了,就是它所在的目录)一起具备了一种带有优先级的层次关系,这对于保证Java程序的稳定运作很重要。例如,类java.lang.Object类存放在JDK\jre\lib下的rt.jar之中,因此无论是哪个类加载器要加载此类,最终都会委派给启动类加载器进行加载,这边保证了Object类在程序中的各种类加载器中都是同一个类。

(3): 类加载器的特点

Java提供了动态的加载特性;它会在运行时的第一次引用到一个class的时候对它进行加载和链接,而不是在编译期进行。JVM的类装载器负责动态加载。

Java类装载器有如下几个特点:

5.4 运行时数据区

运行时数据区是在JVM运行的时候操作系统所分配的内存区。它可以划分为几个区域:方法区,堆,java栈,pc寄存器,本地方法栈等。

image

5.5 执行引擎(****Execution Engine****)

5.5.1 执行引擎的定义

 通过类装载器装载的,被分配到JVM的运行时数据区的字节码会被执行引擎执行。执行引擎以指令为单位读取Java字节码。它就像一个CPU一样,一条一条地执行机器指令。每个字节码指令都由一个1字节的操作码和附加的操作数组成。执行引擎取得一个操作码,然后根据操作数来执行任务,完成后就继续执行下一条操作码。在执行引擎执行时,有一个任务是必须把字节码转换成可以直接被JVM执行的语言,也就是机器码。

5.5.2 字节码的执行技术

主要的执行技术有:解释,即时编译,AOT编译等几种。

其中编译和解释执行的技术有时候是混合在一起的,如果单独从编译技术的角度来看,又分为:前端编译、即时编译(JIT编译)、静态提前编译(AOT编译)三种。

目前主要还是采用解释器+JIT编译这种混合的方式,如JDK中的HotSpot虚拟机。 AOT的编译器在IBM JDK1.6的时候被引入进去,不过主流的jdk用的还是比较少。另外JIT编译速度及编译结果的优劣,是衡量一个JVM性能的很重要的指标,****所以对程序运行性能优化集中到这个阶段;****也就是说可以对这个阶段进行JVM调优;

HotSpot JVM 内置了两个不同的即时编译器,分别称为Client Compiler(C1)和Server Compiler(C2),HotSpot默认采用解释器和其中一个编译器直接配合的方式工作,使用哪个编译器取决于虚拟机运行的模式,HotSpot会根据自身版本和宿主机器硬件性能自动选择模式C1还是C2,用户也可以使用“-client”或”-server”参数去指定。

6.后记

研究jvm,并不是需要我们能写一个jvm,而是要求我们最起码对代码的执行有一个比较清晰的认识,当以后遇到程序比较复杂的场景,可以根据我们的业务需求定制自己的虚拟机,对虚拟机进行调优。

目前我们现在说的Java虚拟机基本上都是JDK自带的虚拟机HotSpot,这款虚拟机也是目前商用虚拟中市场份额最大的一款虚拟机,可以通过在命令行程序中输入“java -version”来查看:

image

那其实市面上还有很多别的优秀的虚拟机。Sun公司除了有大名鼎鼎的HotSpot外,还有KVM、Squawk VM、Maxine VM,BEA公司有JRockit VM、IBM公司有J9 VM等等。

转载地址:http://www.cnblogs.com/haitaofeiyang/p/7744620.html

上一篇 下一篇

猜你喜欢

热点阅读