JVM快速入门(一)——JVM的体系结构

1 什么是JVM

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

2 JRE/JDK/JVM是什么关系


JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台。所有的Java 程序都要在JRE下才能运行。普通用户如果只需要运行已开发好的java程序,而不用编程开发,只安装JRE即可。

JDK(Java Development Kit),是程序开发者用来来编译、调试java程序用的开发工具包。JDK的工具也是Java程序,也需要JRE才能运行。为了保持JDK的独立性和完整性,在JDK的安装过程中,会自动另外安装一个JRE,这个JRE也是安装的一部分。所以,在JDK的安装目录下有一个名为jre的目录,存放JRE文件。

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

JVM -- java virtual machineJVM就是我们常说的java虚拟机,它是整个java实现跨平台的最核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行,class文件并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行,类似于C#中的CLR。

JVM不能单独搞定class的执行,解释class的时候JVM需要调用解释所需要的类库lib。在JDK下面的的jre目录里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib和起来就称为jre。JVM+Lib=JRE,如果讲的具体点就是bin目录下的jvm.dll文件, jvm.dll无法单独工作,当jvm.dll启动后,会使用explicit的方法(就是使用Win32 API之中的LoadLibrary()与GetProcAddress()来载入辅助用的动态链接库),而这些辅助用的动态链接库(.dll)都必须位 于jvm.dll所在目录的父目录之中。因此想使用哪个JVM,只需要设置PATH,指向JRE所在目录下的jvm.dll。


 

3. JVM与操作系统

为什么要在程序和操作系统中间添加一个JVM? Java是一门抽象程度特别高的语言,提供了自动内存管理等一系列的特性。这些特性直接在操作系统上实现是不太可能的,所以就需要JVM进行一番转换。

从图中可以看到,有了JVM这个抽象层之后,Java就可以实现跨平台了。JVM只需要保证能够正确执行.class文件,就可以运行在诸如Linux、Windows、MacOS等平台上了。 而Java跨平台的意义在于一次编译,处处运行,能够做到这一点JVM功不可没。比如我们在Maven仓库下载同一版本的jar包就可以到处运行,不需要在每个平台上再编译一次。 现在的一些JVM的扩展语言,比如Clojure、JRuby、Groovy等,编译到最后都是.class文件,Java语言的维护者,只需要控制好JVM这个解析器,就可以将这些扩展语言无缝的运行在JVM之上了。 应用程序、JVM、操作系统之间的关系

JVM是运行在操作系统之上的,它与硬件没有直接的交互

JVM上承开发语言,下接操作系统,它的中间接口就是字节码。

4 JVM的组成

 

1、类装载器

类装载器的作用是加载通过javac编译的class文件到内存中。Class Loader 加载的class 文件是有格式要求,在《JVM Specification 》中式这样定义Class 文件的结构:

ClassFile {
      u4 magic;
      u2 minor_version;
       u2 major_version;
      u2 constant_pool_count;
      cp_info constant_pool[constant_pool_count-1];
      u2 access_flags;
      u2 this_class;
      u2 super_class;
      u2 interfaces_count;
      u2 interfaces[interfaces_count];
      u2 fields_count;
      field_info fields[fields_count];
      u2 methods_count;
      method_info methods[methods_count];
      u2 attributes_count;
      attribute_info attributes[attributes_count];
    }

注:Class Loader 只管加载符合文件结构的class文件,至于说能不能运行,则不是它负责的,那是由Execution Engine 负责的。
 

2、Execution Engine 执行引擎

执行引擎也叫作解析器(Interpreter),负责解析命令,提交操作系统执行。

3、Native Interface 本地接口

本地接口的作用是融合不同的编程语言为Java 所用,初衷是融合C/C++ 程序。Java 诞生的时候是C/C++ 横行的时候,要想立足,必须有一个聪明的、睿智的调用C/C++ 程序,于是就在内存中专门开辟了一块区域处理标记为native 的代码。具体做法是Native Method Stack 中登记native 方法,在Execution Engine 执行时加载native libraies(本地方法库) 。
目前该方法使用的是越来越少了,除非是与硬件有关的应用,比如通过Java 程序驱动打印机,或者Java 系统管理生产设备,在企业级应用中已经比较少见,因为现在的异构领域间的通信很发达,比如可以使用Socket 通信,也可以使用Web Service 等等,不多做介绍。

4、Runtime data area 运行时数据区

运行数据区是整个JVM的重点,java虚拟机在执行java程序的过程中会把他所管理的内存划分为若干个不同的数据区域:Method Area(方法区)、VM stack(虚拟机栈或者称本地方法栈)、Native Method Stack(本地方法栈)、Heap(堆)、Program Counter Register(程序计数器)。

(1)Program Counter Register(程序计数器)

  • 占用较小的内存空间,
  • 线程私有,生命周期与线程相同。每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储;
  • 当前线程执行的字节码的行号指示器,字节码解析器通过改变计数器的值来选择下一条需要执行的字节码指令;
  • 分支、循环、跳转、异常处理、线程恢复都依赖计数器来完成;
  • 唯一 一个在java虚拟机规范中没有规定任何OutOfMemeryError情况的区域;

(2)VM Stack(java虚拟机栈)

  • 线程私有,生命周期与线程相同,不存在垃圾回收,线程结束,内存释放;
  • 每个方法在执行的同时会创建一个栈帧(方法运行时的基础数据结构);
  • 线程请求的栈深度超过虚拟机允许的最大深度,会抛出StackO
  • java虚拟机规范中运行固定长度的虚拟机栈;
  • 虚拟机栈允许动态扩展,扩展时申请不到足够的内存,则会抛出OutOfMemoryError异常;
  • 栈帧用来存储:局部变量表、操作数栈、动态链接、方法出口等;
  • 局部变量表:编译器可知的基本数据类型、对象引用、returnAddresss。所需内存在编译器完成分配,运行期间不会改变;
    基本数据类型:Boolean 、byte、short、char、int、float、long、double,64位长度的double和long占两个局部
     
    对象引用:可能指向一个对象的起始地址的引用指针、也可能指向一个代表对象的句柄或者于此对象相关的位置
    
    returnAddress:指向一条字节码指令的地址;
    

(3)Native Method Stack(本地方法栈) 

  • 登记native方法,在Execution Engine执行引擎执行时,通过Native Interface 本地接口调用已登记的native library;
  • 为虚拟机使用的Native方法服务,简单来说就是一个java调用非java代码。
  • java需要与一些底层系统如操作系统或某些硬件交换信息,如调用打印机;

(4)Heap(堆)也被称为“GC堆”

  • 所有线程共享
  • 虚拟机管理的内存中最大的一块。
  • 垃圾收集器管理的主要区域,因此很多时候也被称作“GC堆”;
  • 存放对象实例,几乎所有的对象实例及数组都在堆中分配内存;

(5)Method Area (方法区)

  • 所有线程共享
  • Non-Heap(非堆);
  • 在HotSpot虚拟机又被称为“永久代”;
  • 存储已被虚拟机加载的类信息(构造方法,接口定义)、静态变量、常量、即时编译器编译后的代码等数据;
  • 并非数据进入方法区就如“永久代”的名称一样永久存在了,这一区域的回收目标主要是针对常量池的回收和对类型的卸载。

(6)重要:栈和堆区分的原因

  • 从软件设计的角度看,栈代表了逻辑处理,堆代表数据。两者区分使得处理逻辑更为清晰
  • 堆中内存可以被多个栈共享(可以理解为多个线程可以访问同一个对象)
  • 栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分。由于栈基本只能向上增长(占内存较小,所以动态扩展的可用内存有限),也就限制了栈存储内容的能力。而堆不同,堆可以根据需要动态增长。因此栈和堆得划分,也使得动态增长成为可能,相应的栈中只需要记录堆中的一个地址即可

(7)java 对象内存示例

Demo demo=new Demo();

Demo demo;//创建对象引用
demo=/将对象引用指向对象 /new Demo(); //创建对象
只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。

原文链接:JVM(一)- 组成部分及详解_小狐狸Rosie的博客-CSDN博客_jvm组成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JagTom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值