JVM小解及总结

来源:互联网 发布:java 反射写法 编辑:程序博客网 时间:2024/05/16 04:20

    JVM:Java虚拟机(Java Virtual Machine

    JDK:Java开发工具(Java Developer  Kit)

    JRE:Java运行环境(Java Runtime Environment )

    

                                              图1、JVM模型简图

1、JVM简述

        JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 

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

       *运行时:.class文件信息加载到JVM中并调用的过程

       *编译时:.java的源代码文件变成.class文件的过程

  JVM是JRE的一部分。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java语言最重要的特点就是跨平台运行。使用JVM就是为了支持与操作系统无关,实现跨平台。所以,JAVA虚拟机JVM是属于JRE的,而现在我们安装JDK时也附带安装了JRE(当然也可以单独安装JRE)。

2、JVM内存区域划分

  粗略分来,JVM的内部体系结构分为三部分,分别是:类装载器(ClassLoader)子系统,运行时数据区(Runtime Data Area),和执行引擎(Execution Engine)

3、类装载器(ClassLoader)

        每一个Java虚拟机都由一个类加载器子系统(class loader subsystem),负责加载程序中的类文件(类和接口),并赋予唯一的名字。每一个Java虚拟机都有一个执行引擎(execution engine)负责执行被加载类中包含的指令。JVM的两种类装载器包括:启动类装载器和用户自定义类装载器,启动类装载器是JVM实现的一部分,用户自定义类装载器则是Java程序的一部分,必须是ClassLoader类的子类。

4、执行引擎:它或者在执行字节码,或者执行本地方法

       主要的执行技术有:解释,即时编译,自适应优化、芯片级直接执行其中解释属于第一代JVM,即时编译JIT属于第二代JVM,自适应优化(目前Sun的HotspotJVM采用这种技术)则吸取第一代JVM和第二代JVM的经验,采用两者结合的方式 。

       自适应优化:开始对所有的代码都采取解释执行的方式,并监视代码执行情况,然后对那些经常调用的方法启动一个后台线程,将其编译为本地代码,并进行仔细优化。若方法不再频繁使用,则取消编译过的代码,仍对其进行解释执行。

5、运行时数据区:主要包括:方法区,堆,虚拟机栈,PC寄存器,本地方法栈

   

 5.1、堆(Heap):

        存放的内容:此内存区域的唯一目的就是存放对象实例(和数组),几乎所有的对象实例都在这里分配内存。每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令) 

        类与实例的关系:.class文件,封装 这个类的一系列信息(属性、方法、构造方法),使用该类的信息可以创建一个具体的实例对象。比如:香肠机器和香肠的关系,香肠机器中就包含制造香肠的原料、制造香肠的方法、步骤,按照香肠机器的信息,就可以制造出一个香肠,但每一个香肠都是一个独立的香肠。


5.2、方法区(静态区 Method Area):

        存放的内容:虚拟机加载的类信息(class)、常量(final)、静态变量(static)、即时编译器编译后的代码等数据  。

简单说方法区用来存储类型的元数据信息,一个.class文件是类被java虚拟机使用之前的表现形式,一旦这个类要被使用,java虚拟机就会对其进行装载、连接(验证、准备、解析)和初始化。而装载(后的结果就是由.class文件转变为方法区中的一段特定的数据结构。这个数据结构会存储如下信息:

类型信息:
      这个类型的全限定名
      这个类型的直接超类的全限定名
      这个类型是类类型还是接口类型
      这个类型的访问修饰符
      任何直接超接口的全限定名的有序列表
 
字段信息:
      字段名
      字段类型
      字段的修饰符
 
方法信息:
      方法名
      方法返回类型
      方法参数的数量和类型(按照顺序)
      方法的修饰符
 
其他信息:
      除了
常量(final)以外的所有类(static)变量
      一个指向ClassLoader的指针
      一个指向Class对象的指针
      常量池(常量数据以及对其他类型的符号引用,这个是
运行时常量池区别于String常量池

  当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,同时方法区域也是全局共享的,

在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。

*方法区和堆由所有线程共享

*虚拟机栈和PC寄存器由线程独享

5.3、栈(stack)    

JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址

  • VM Stack(虚拟机栈):虚拟机只会直接对Javastack执行两种操作:以帧为单位的压栈或出栈

    每个帧代表一个方法,Java方法有两种返回方式,return和抛出异常,两种方式都会导致该方法对应的帧出栈和释放内存。

    帧的组成:局部变量区(包括方法参数和局部变量,对于instance方法,还要首先保存this类型,其中方法参数按照声明顺序严格放置,局部变量可以任意放置),操作数栈,帧数据区(用来帮助支持常量池的解析,正常方法返回和异常处理)。

  • ProgramCounter(程序计数器) 

        程序计数器是用于存放下一条指令所在单元的地址的地方。
当执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中,此过程称为“取指令”。与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令。

 每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。

若thread执行Java方法,则PC保存下一条执行指令的地址。若thread执行native方法,则PC的值为undefined

  • Nativemethodstack(本地方法栈):保存native方法进入区域的地址

    依赖于本地方法的实现,如某个JVM实现的本地方法借口使用C连接模型,则本地方法栈就是C栈,可以说某线程在调用本地方法时,就进入了一个不受JVM限制的领域,也就是JVM可以利用本地方法来动态扩展本身。


结语:

理解JVM有什么作用呢?对于反射技术中对类的动态加载(程序运行时根据类的全限定名来加载需要使用到的类)十分有帮助。
   注意区别以下几个概念:编译时、运行时、运行时常量池、String常量池等等。




参考文章:http://blog.csdn.net/stanlee_0/article/details/51171382

 如有雷同,欢迎指正,图片来源网络。