2019独角兽企业重金招聘Python工程师标准>>>
JVM 架构解释
每个Java开发者都知道通过JRE【Java运行环境】执行字节码。
但是很多人都不知道JRE是JVM实现的事实。JVM负责执行字节码的分析
代码的解释和运行。
我们应该了解JVM的架构,这对开发者来说是很重要的,这促进我们更有效的
编写代码。在本文中,我们将深入学习有关JVM的架构和JVM组件的区别。
什么是JVM?
虚拟机是物理机的一个软件实现。
JAVA是基于WORA(一次编写,到处运行)的概念开发的,它运行在虚拟机上。
编译器将Java文件编译成class文件,然后将class文件输入到JVM,JVM加载并运行class文件。
下面是JVM架构图:
JVM是如何工作的?
像上面图表显示那样,JVM分成3个主要的子系统:
- 类加载器子系统
- 运行时数据区
- 执行引擎
1、类加载器子系统
Java的动态类加载功能是通过类加载子系统去处理的。
它并不是在编译时候,而是在首次运行时加载引用类时、连接并初始化类文件。
1.1 加载
类通过该组件加载。通过引导类加载器,扩展类加载器,应用类加载器这三个类加载器帮助完成加载。
- 引导类加载器
负责从引导类路径去加载类,除了rt.jar之外,没其他别的jar。给予该加载器最高的优先级。
- 扩展类加载器
负责加载ext目录(jre\lib)的类
- 应用加载器
负责加载类路径中应用级别的类,path提到的环境变量,等等。
以上的类加载器在加载类文件的时候遵循委托层次算法。
1.2连接
- 验证-字节码验证器验证生成的字节码是否正确,如果验证失败,我们将收到验证的错误信息。
- 准备-为所有的静态变量分配内存和默认值
- 解析-用方法区的原始引用代替所有符号内存引用。
1.3 初始化
这是类加载的最后一个阶段,此时所有的静态变量都用原始值去赋值,并且将运行静态代码块。
2、运行时数据区
运行时数据区域分成5个主要的组件:
- 方法区-所有类级的数据都存储在这里,包括静态变量。
每个JVM只有一个方法区,它是一个共享资源。
- 堆区-所有的对象和对应的实例变量以及数组都存储在这里。
每个JVM只有一个堆区,由于方法区和堆区为多个线程共享内存,所以
存储的数据不是线程安全的。
- 栈区-为每个线程,创建一个单独的运行时栈。为每个方法调用,在栈内存创建一个条目,称之为栈帧。所有本地变量都会在栈内存中创建。由于它不是共享的资源,所有是线程安全的。
栈帧被分成3子实体
- 本地变量数组-涉及跟方法有关的本地变量和对应的值都存储在这里。
- 操作数栈-如果需要执行中间操作,操作数堆栈作为运行时工作区来执行操作。
- 帧数据-所有和对应方法的标记都存储在里面。在发生异常的情况下,捕捉块信息在这里维护。
- 程序计数器寄存器--每个线程都有自己的程序计数器寄存器,持有当前执行指令的地址,一旦当前指令执行被运行,下一个指令将会更新到程序计数器寄存器。
3、执行引擎
字节码被分配到执行引擎执行的运行时数据区。执行引擎一块一块的读取字节码并执行。
- 解释器-解释器解释字节码很快,但是执行的很慢。解释器的缺点是当一个方法被调用多次,每次都需要一个新的解释。
- JIT编译器-JIT弥补了解释器的缺点。执行引擎将利用解释器转换字节码,但是当他找到重复的编码,它就使用编译器。编译器编译全部的字节码并变成本地代码
这些本地码将直接被方法调用重复地使用,这就改善了系统的性能。
- 中间代码生成器-生成中间代码。
- 代码优化器-负责优化上面生成的代码
- 目标代码生成器-负责生成机器码或者本地代码
- 分析器-一个特殊的组件,负责寻找hotspots,即是否方法被调用多次。
- 垃圾收集器:收集和清除未被引用的对象,可以通过System.gc()触发垃圾回收,但是不保证一定执行。创建收集对象的JVM垃圾收集。
Java Native Interface (JNI):JNI和本地方法库互动,特供本地库所需的执行引擎。
Native Method Libraries: 这是执行引擎所需的本地方法的一个集合
本文为在下翻译外文的处女作,水平有限,翻译不恰当之处,烦请读者指正!
原文地址:https://dzone.com/articles/jvm-architecture-explained