美文网首页我爱编程
深入了解java虚拟机!

深入了解java虚拟机!

作者: 小菜一碟i | 来源:发表于2017-12-08 10:55 被阅读34次

    虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行

    Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。

    Java虚拟机是Java语言底层实现的基础。这有助于理解Java语言的一些性质,也有助于使用Java语言。对于要在特定平台上实现Java虚拟机的软件人员,Java语言的编译器作者以及要用硬件芯片实现Java虚拟机的人来说,则必须深刻理解Java虚拟机的规范。另外,如果你想扩展Java语言,或是把其它语言编译成Java语言的字节码,你也需要深入地了解Java虚拟机。

    JAVA虚拟机的生命周期

    一个运行时的Java虚拟机实例的天职是:负责运行一个java程序。当启动一个Java程序时,一个虚拟机实例也就诞生了。当该程序关闭退出,这个虚拟机实例也就随之消亡。如果同一台计算机上同时运行三个Java程序,将得到三个Java虚拟机实例。每个Java程序都运行于它自己的Java虚拟机实例中。

    Java虚拟机实例通过调用某个初始类的main()方法来运行一个Java程序。而这个main()方法必须是共有的(public)、静态的(static)、返回值为void,并且接受一个字符串数组作为参数。任何拥有这样一个main()方法的类都可以作为Java程序运行的起点。

    在上面的例子中,Java程序初始类中的main()方法,将作为该程序初始线程的起点,任何其他的线程都是由这个初始线程启动的。

    在Java虚拟机内部有两种线程:守护线程和非守护线程。守护线程通常是由虚拟机自己使用的,比如执行垃圾收集任务的线程。但是,Java程序也可以把它创建的任何线程标记为守护线程。而Java程序中的初始线程——就是开始于main()的那个,是非守护线程。

    只要还有任何非守护线程在运行,那么这个Java程序也在继续运行。当该程序中所有的非守护线程都终止时,虚拟机实例将自动退出。假若安全管理器允许,程序本身也能够通过调用Runtime类或者System类的exit()方法来退出。

    JAVA虚拟机的体系结构

    下图是JAVA虚拟机的结构图:

    每个Java虚拟机都有一个类装载子系统,它根据给定的全限定名来装入类型(类或接口)。同样,每个Java虚拟机都有一个执行引擎,它负责执行那些包含在被装载类的方法中的指令。 当JAVA虚拟机运行一个程序时,它需要内存来存储许多信息,Java虚拟机把这些信息都组织到几个“运行时数据区”中,以便于管理。运行时数据区共包括五个部分(方法区、Java堆区、Java栈区、程序计数器、本地方法栈)。

    1.类加载子系统

    在JAVA虚拟机中,负责查找并加载类型的那部分被称为类加载子系统。

    类加载器子系统在Java虚拟机中实现了类加载的全过程动作,这些动作必须严格按以下顺序进行:

    (1)加载——主要完成3件事:

    1.通过一个类的全限定名来获取定义此类的二进制字节流。

    2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

    3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

    (2)连接——指向验证、准备、以及解析(可选)。

    ● 验证 确保Class文件的字节流中包含的的信息符合当前虚拟机的要求,并且不会危害到虚拟机自身的安全。

    ● 准备 为类变量分配内存,并将其初始化为默认值。

    ● 解析 把类型中的符号引用转换为直接引用。

    (3)初始化——把类变量初始化为正确初始值。

    类加载器:用来加载 Java 类到 Java 虚拟机中,实现“通过一个类的全限定名来获取描述此类的二进制字节流”动作的代码模块。

    对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器都拥有一个独立的类名称空间。也就是说,比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义。

    JAVA虚拟机有两种类加载器:启动类加载器和用户自定义类加载器。前者由C++实现,是JAVA虚拟机实现的一部分;后者则是由Java程序实现,独立于虚拟机外部。

    数据类型

    Java虚拟机是通过某些数据类型来执行计算的,数据类型可以分为两种:基本类型和引用类型,基本类型的变量持有原始值,而引用类型的变量持有引用值。

    Java语言中的所有基本类型同样也都是Java虚拟机中的基本类型。但是boolean有点特别,虽然Java虚拟机也把boolean看做基本类型,但是指令集对boolean只有很有限的支持,当编译器把Java源代码编译为字节码时,它会用int或者byte来表示boolean。在Java虚拟机中,false是由整数零来表示的,所有非零整数都表示true,涉及boolean值的操作则会使用int。另外,boolean数组是当做byte数组来访问的,但是在“堆”区,它也可以被表示为位域。

    Java虚拟机还有一个只在内部使用的基本类型:returnAddress,Java程序员不能使用这个类型,这个基本类型被用来实现Java程序中的finally子句。该类型是jsr, ret以及jsr_w指令需要使用到的,它的值是JVM指令的操作码的指针。returnAddress类型不是简单意义上的数值,不属于任何一种基本类型,并且它的值是不能被运行中的程序所修改的。

    Java虚拟机的引用类型被统称为“引用(reference)”,有三种引用类型:类类型、接口类型、以及数组类型,它们的值都是对动态创建对象的引用。类类型的值是对类实例的引用;数组类型的值是对数组对象的引用,在Java虚拟机中,数组是个真正的对象;而接口类型的值,则是对实现了该接口的某个类实例的引用。还有一种特殊的引用值是null,它表示该引用变量没有引用任何对象。

    相关文章

      网友评论

        本文标题:深入了解java虚拟机!

        本文链接:https://www.haomeiwen.com/subject/suxeixtx.html