JVM之(一)概述

来自:http://www.haogongju.net/art/1223673

一、JVM的概念

通常我们所提到的“JVM”有着多重的意义,一般来讲,JVM既可以用来描述一个“抽象规范”,也可以用来描述一个规范的具体实现,同时还可以用来一个运行中的虚拟机实例。而JVM具体指这些含义中的哪一个,要根据该词所处的上下文环境来进行分析

二、JVM的生存周期

一个JVM的作用就是用来负责运行一个Java程序,当该程序启动时,一个JVM实例也就产生了,当该程序运行完毕退出时,该JVM实例也就随之消亡了。

只要有任何非守护线程[1]在运行,Java程序也就在继续运行,JVM也就在存活状态之中。当程序中所有的非守护线程都终止时,JVM实例将退出。

三、JVM的数据类型

四、JVM系统结构

 

4.1 类装载子系统

4.1.1类装载器子系统的作用

类装载子系统是JVM中负责查找并装载类型的子系统。

JVM对于每个被装载的类型,都会创建一个java.lang.Class类实例来代表该类型。

类装载子系统除了要定位和导入二进制class文件时外,还必须负责验证被导入类的正确性为类变量分配并初始化内存,以及帮助解析符号引用

4.1.2类装载器的分类

JVM中包含两种类装载器:启动类装载器和用户定义的类装载器。前者是JVM实现的一部分,而后者则是使用Java语言实现,是Java程序的一部分。

4.1.2.1 启动类装载器

每个JVM都必须有一个启动类装载器,它知道如何去装载受信任的类(如Java类库等)。

4.1.2.2 用户自定义的类装载器

用户自定义的类载器必须派生自java.lang.ClassLoader类,主要通过以下几个方法来处理类装载:

(1)protected final Class<?> defineClass(String name, byte[] b, int off, int len)

(2)protected final Class<?> defineClass(String name, byte[] b, int off, int len,

                   ProtectionDomain protectionDomain)

方法(1)和方法(2)负责定义一个新的类型。

(3)protected final Class<?> findSystemClass(String name)

    throws ClassNotFoundException

(4)protected final void resolveClass(Class<?> c)

方法(3)根据类的全限定名来使用系统类装载器来装载该类型。

方法(4)对类型的Class实例来执行连接动作。

4.1.3命名空间

在JVM中,每个类装载器都有自己的命名空间,在该空间内维护着由其负责装载的类型。命名空间其实是一种解析过程的结果。对于每一个被装载的类型,JVM都会记录装载它的类装载器,当JVM解析到一个类到另外一个类的符号引用时,它需要被引用类的类装载器。

类装载器名称+类型的全限定名构成了类型的唯一标识。

4.2 方法区

方法区是所有线程共享的,因此方法区数据的访问必须实现为线程安全的。方法区只是一个逻辑上的概念,它并不要求实际上其大小必须是固定的,也不必是连续的内存。方法区可以在一个堆(甚至是虚拟机自己的堆)中自由分配,也可以允许用户或者程序员来指定方法区的初始大小及最大最小尺寸等。

方法区是可以被垃圾回收器回收的。

4.2.1方法区的作用

在JVM中,被装载的类型信息存储在一个逻辑上称作“方法区”的内存中。当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件(二进制线性数据流),然后将其传输到JVM中,然后JVM提取出其中的类型信息,并将这些信息存储到方法区。该类型中的类变量也是存储在方法区的。

4.2.2方法区存储的具体信息

l         类的全限定名

l         类的直接超类的全限定名(java.lang.Object不需要)

l         类类型还是接口类型

l         类型的访问修改

l         直接超接口的全限定名的有序列表

l         常量池[2]

l         字段信息

  • 字段的声明顺序
  • 字段名
  • 字段类型
  • 修饰符

l         方法信息

  • 方法声明的顺序
  • 方法名
  • 方法的返回类型
  • 方法参数的数量和类型(按声明顺序)
  • 方法的修饰符
  • 方法的字节码、操作数栈和局部变量区的大小、异常表(非abstract和native的方法)

l         除常量外的所有类变量

l         一个到类ClassLoader的引用

l         一个到Class类的引用

4.3 堆

Java程序在运行时创建的所有类实例或数组都存储在同一个堆中。一个Java虚拟机实例中只存在一个堆空间,所有线程都共享这个堆空间,因此,堆空间数据的访问也是要求要线程安全的。

堆空间也不要求是连续的内存空间,它可以动态扩展。

4.3.1数组的内部实现

在Java中,数组是真正的对象。数组总是存储在堆中。同其它所有对象一样,数组也拥有一个与它们的类相关联的Class实例,所有具有相同维度和类型的数组都是同一个类的实例,而不管数组的长度(多维数组每一维的长度)是多少。

数组类的名称由两部分组成,每一维用一个方括号“[”表示,用字符或字符串表示元素类型。如[I,[[Ljava/lang/Object。

4.4 Java栈

当启动一个线程时,JVM都会为它分配一个Java栈。JVM只对会Java栈进行两种操作:压栈和出栈。当线程调用一个方法时,JVM都会在该线程的Java栈中压入一个新帧。

Java栈上的所有数据都是线程私有的。任何一个线程都不能访问另一个线程上的栈数据。

Java栈和帧在内存中也不必是连续的。

4.4.1桢帧

栈帧由在三部分组成:局部变量区、操作数栈和帧数据区。局部变量区和操作数栈的大小在编译时就会计算完毕,存储在class文件中。帧数据区的大小要视具体的实现而定。

当虚拟机调用一个Java方法时,它从对应的类信息中得到此方法的局部变量区和操作数栈的大不,并据此分配内存,然后压入到Java栈中。

4.4.1.1 局部变量区

局部变量区是以一个以字长为单位,从0开始计算的数组。字节码指令通过从0开始的索引来使用其中的数据。类型为int, float, reference和returnAddress的值在数组中占一项,而类型为byte, short和char的值在存储数组之前都会强制转换为int类型,也占一项。类型为long和double类型的值在数组中占据连续的两项。

局部变量区包含对应方法的参数和变量,编译器首先按照声明的顺序将其放到局部变量数组。

4.4.1.2 操作数栈

操作数栈与局部变量区一样,也是被组织成一个以字长为单位的数组,但其并不通过索引来访问,而是通过标准的栈操作:压栈和出栈来访问的。

4.4.1.3 帧数据区

除了局部变量区和操作数栈外,Java栈帧还需要一些数据来支持常量池解析、正常方法返回和异常派发机制。这些信息都保存在帧数据区中。

4.5 程序计数器

对于每一个运行中的Java程序而言,其中的每一个线程都有属于自己的PC(程序计数器)寄存器,在线程创建时创建PC。PC寄存器的大小是一个字长。在线程执行Java方法时,PC寄存器的内容总是指向下一条将被执行指令的“地址”,这里的“地址”可以是一个本地指针,也可以是在方法字节码中相对于该方法起始指令的“偏移量”。如果该线程正在执行的是本地方法,PC寄存器中的值是“undefined”。

4.6 本地方法栈

任何本地方法接口都会使用某种本地方法栈。当线程调用Java方法时,虚拟机会创建一个新的栈帧并压入到Java栈。当其调用到本地方法时,虚拟机会保护Java栈不变,不再在线程的Java栈中压入新的栈帧,虚拟机只是简单地动态连接并直接调用指定的本地方法。这可以看作是虚拟机利用本地方法来动态地扩展自己。

如果某个虚拟机实现的本地方法接口是使用C连接模型的话,那么它的本地方法栈就是C栈。

本地方法栈占用的内存区也不必是固定大小的,它可以根据需要动态扩展或收缩。某些实现也允许用户或者程序员指定该内存区的初始大小及最大、最小值。

4.7 执行引擎

JVM的核心是其执行引擎部分。在JVM规范中,执行引擎的行为使用指令集来进行定义。对于每条指令,规范都详细规定了当实现执行到该指令时应该处理什么,但对实现细节没有约束。

4.7.1指令集

方法的字节码流都是由Java虚拟机的指令序列构成的。每一条指令包含一个单字节的操作码,后面跟随0个或多个操作数。操作码表明需要进行的操作;操作数向操作码提供执行时所需要的额外信息。

4.7.2执行技术

实现可以采用多种执行技术:解释、即时编译、自适应优化芯片级直接执行等,只要符合JVM规范中对指令规定的操作即可。

 



[1] 守护线程,通常是由虚拟机自己使用的线程。但Java语言允许将其创建的线程设置为守护线程。Java程序初始运行的初始线程,即main方法所处的线程,是非守护线程。

[2] 常量池是该类型所用常量的一个有序集合,包括直接常量(string, integer和float point常量)和对其它类型、字段、方法的符号引用。其中的数组项访问就像数组一样是通过索引来访问的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值