JVM整体介绍
JAVA技术体系结构
Java虚拟机(Java Virtual Machine 简称 JVM)是运行所有Java程序的抽象计算机,是Java语言的运行环境,它是Java 最具吸引力的特性之一。
Java虚拟机是整个Java技术体系最重要的基础。
为什么要了解虚拟机
首先,Java 虚拟机提供了许多配置参数,用于满足不同应用场景下,对程序性能的需求。学习Java 虚拟机,你可以针对自己的应用,最优化匹配运行参数。
其次,Java 虚拟机本身是一种工程产品,在实现过程中自然存在不少局限性。学习 Java 虚拟机,可以更好地规避它在使用中的 Bug,也可以更快地识别出 Java 虚拟机中的错误
再次,Java 虚拟机拥有当前最前沿、最成熟的垃圾回收算法实现,以及即时编译器实现。学习Java 虚拟机,我们可以了解背后的设计决策,今后再遇到其他代码托管技术也能触类旁通。
最后,Java 虚拟机发展到了今天,已经脱离 Java 语言,形成了一套相对独立的、高性能的执行方案。除了 Java 外,Scala、Clojure、Groovy,以及时下热门的 Kotlin,这些语言都可以运行在 Java 虚拟机之上。学习 Java 虚拟机,便可以了解这些语言的通用机制,甚至于让这些语言共享生态系统。
未来的Java技术
模块化:OSGI(动态化、模块化),应用层面就是微服务,互联网的发展方向
混合语言:多个语言都可以运行在JVM中,google的Kotlin 成为了 Android 的官方语言。Scala(Kafka)
多核并行:CPU从高频次转变为多核心,多核时代。JDK1.7引入了Fork/Join,JDK1.8提出lambda表达式(函数式编程天生适合并行运行)
丰富语法:JDK5提出自动装箱、泛型(并发编程讲到)、动态注解等语法。JDK7二进制原生支持。try-catch-finally 至try-with-resource
64****位:虽然同样的程序64位内存消耗比32位要多一点,但是支持内存大,所以虚拟机都会完全过渡到64位,32位的JVM有4G的堆大小限制。
更强的垃圾回收器(现在主流CMS、G1):JDK11 –ZGC(暂停时间不超过10毫秒,且不会随着堆的增加而增加,TB级别的堆回收)):有色指针、加载屏障。JDK12支持并发类卸载,进一步缩短暂停时间 JDK13(计划于2019年9月)将最大堆大小从4TB增加到16TB
JVM的整体介绍
JVM是如何工作的
JVM分成3个主要的子系统
类加载器子系统
运行时数据区
执行引擎
类加载器子系统
Java的动态类加载功能是通过类加载子系统去处理的。
它并不是在编译时候,而是在首次运行时加载引用类时、连接并初始化类文件。
加载
类通过该组件加载。通过引导类加载器,扩展类加载器,应用类加载器这三个类加载器帮助完成加载。
- 引导类加载器
负责从引导类路径去加载类,除了rt.jar之外,没其他别的jar。给予该加载器最高的优先级。
- 扩展类加载器
负责加载ext目录(jre\lib)的类
- 应用加载器
负责加载类路径中应用级别的类,path提到的环境变量,等等。
以上的类加载器在加载类文件的时候遵循委托层次算法。
连接
- 验证-字节码验证器验证生成的字节码是否正确,如果验证失败,我们将收到验证的错误信息。
- 准备-为所有的静态变量分配内存和默认值
- 解析-用方法区的原始引用代替所有符号内存引用。
初始化
这是类加载的最后一个阶段,此时所有的静态变量都用原始值去赋值,并且将运行静态代码块。
运行时数据区
运行时数据区域分成5个主要的组件
方法区
所有类级的数据都存储在这里,包括静态变量。
每个JVM只有一个方法区,它是一个共享资源。
堆区
所有的对象和对应的实例变量以及数组都存储在这里。
每个JVM只有一个堆区,由于方法区和堆区为多个线程共享内存,所以存储的数据不是线程安全的。
栈区
为每个线程,创建一个单独的运行时栈。为每个方法调用,在栈内存创建一个条目,称之为栈帧。所有本地变量都会在栈内存中创建。由于它不是共享的资源,所有是线程安全的。
栈帧被分成3子实体
- 本地变量数组-涉及跟方法有关的本地变量和对应的值都存储在这里。
- 操作数栈-如果需要执行中间操作,操作数堆栈作为运行时工作区来执行操作。
- 帧数据-所有和对应方法的标记都存储在里面。在发生异常的情况下,捕捉块信息在这里维护。
程序计数器寄存器
每个线程都有自己的程序计数器寄存器,持有当前执行指令的地址,一旦当前指令执行被运行,下一个指令将会更新到程序计数器寄存器。
执行引擎
字节码被分配到执行引擎执行的运行时数据区。执行引擎一块一块的读取字节码并执行。
解释器
解释器解释字节码很快,但是执行的很慢。解释器的缺点是当一个方法被调用多次,每次都需要一个新的解释。
JIT编译器
JIT弥补了解释器的缺点。执行引擎将利用解释器转换字节码,但是当他找到重复的编码,它就使用编译器。编译器编译全部的字节码并变成本地代码
这些本地码将直接被方法调用重复地使用,这就改善了系统的性能。
- 中间代码生成器-生成中间代码。
- 代码优化器-负责优化上面生成的代码
- 目标代码生成器-负责生成机器码或者本地代码
- 分析器-一个特殊的组件,负责寻找hotspots,即是否方法被调用多次。
垃圾收集器
收集和清除未被引用的对象,可以通过System.gc()触发垃圾回收,但是不保证一定执行。创建收集对象的JVM垃圾收集。
Java Native Interface (JNI):JNI和本地方法库互动,特供本地库所需的执行引擎。
Native Method Libraries: 这是执行引擎所需的本地方法的一个集合