一、定义
二、特性
三、核心概念
0、即时编译
(1)定义
即时编译,也叫JIT,它是一种提升程序执行效率的编译技术。JVM会先解释执行程序代码,然后把程序中的反复执行的热点代码即时编译成机器码,直接运行在硬件上,提高程序执行效率。
热点代码的判定:根据方法调用次数和循环回边次数。
(2)种类
A、C1编译
B、C2编译
C、分层编译
D、Graal编译
E、OSR编译
1、JVM运行时区域构成
2、类的加载机制
(1)定义
类的加载指JVM把class文件加载到JVM内存中的过程。
注意:
- Java的基本类型对应的类对象由JVM预先定义好;
- 数组由于没有对应的字节流,所以JVM直接生成数组的类对象。
(2)3个阶段
A、加载
JVM通过类加载器从各种源中查找class文件转成字节流并加载到内存中且创建对应的类对象。
加载源:
- 由Java编译器生成的class文件
- 在程序内部生成的class文件
- 从网络中获取的class文件
类加载器
-
定义
类加载器是一个从各种源中找到对应的class文件并转为字节流、加载进JVM内存的工具。
类加载器的加载规则:
JVM中的类加载器遵循双亲委派机制的规则。每当一个类加载器接收到加载请求时,它会把请求转发给父类加载器。在父类加载器没有找到所请求的类的情况下,该类加载器才会去尝试加载类。
-
种类
- 启动类加载器:启动类加载器由c++实现,没有对应的Java对象。启动类加载器负责加载最基础和最重要的类,比如存放在JRE/lib下的jar中的类,以及参数-Xbootclasspath指定的类。
- 扩展类加载器(JDK9改名为平台类加载器):扩展类加载器的父类是启动类加载器。扩展类加载器负责加载相对次要、通用的类,比如存放在JRE/lib/ext下jar包中的类,以及系系统变量java.ext.dirs指定的类。
- 应用类加载器:应用类加载器的父类是扩展类加载器。应用类加载器负责加载应用程序类路径下的类,即参数-cp/-classpath、系统变量java.class.path或环境变量CLASSPATH指定的路径。默认情况下,应用程序中包含的类都是由应用类加载器加载。
- 自定义类加载器:通过自定义类加载器,可以实现特殊的加载方式。比如,利用自定义类加载器对加密的class文件进行解密等。
注意:除了启动类加载器由c++实现,其中类加载器都是java.lang.ClassLoaderd的子类,都有对应的Java对象。因此,这些Java实现的类加载器使用前都需要由另一个类加载器(比如启动类加载器)加载到JVM内存中。
B、链接
a、定义
链接是负责验证类的有效性并为类的可执行做好准备的过程。
b、3个阶段
- 验证:确保被加载的类对象符合JVM的约束条件
- 准备:为被加载的类对象的静态字段分配内存
- 解析:把类对象中的符号引用转为实际引用。若该符号引用指向的是一个未加载的类,会触发该类的加载。该解析过程的时间并不一定会在链接过程中完成,有可能和初始化过程并行执行。
C、初始化
初始化阶段是对final常量字段赋值以及执行clinit方法(只会被执行一次),clinit方法是对所有静态代码块的执行。
触发初始化的时机:
- 初始化用户指定的主类
- 初始化new指令的目标类
- 初始化被调用静态方法所在的类
- 初始化被访问静态字段所在的类
- 子类初始化会触发父类的初始化
- 若直接或间接实现某个接口的default方法的类发生初始化,会触发该接口的初始化
- 反射调用某个类时,会触发该类的初始化
- 初次调用MethodHandle实例时,初始化该MethodHandle指向的方法所在的类
- 关于MethodHandle的认识:JVM角度看方法调用-MethodHandle篇 - 知乎
注意:只有初始化完毕后,类才正式成为可执行的状态。
3、垃圾回收(GC)
(1)定义
垃圾回收,又叫GC。JVM在垃圾回收时,会先通过引用计数法或者可达性分析法,标记出不再使用的对象(即垃圾),接着JVM会对这些垃圾进行回收。
- 引用计数法:
- 定义:每个对象都维护一个计数器,当对象被另一个对象引用时,则引用计数器加1,当对象不再被另一个对象引用时,则引用计数器减1。当引用计数器为0时,则证明该对象不再被使用,这种对象也叫垃圾。
- 优点和缺点:引用计数法实现简单,判断效率高,但由于存在对象之间循环引用问题,所以引用计数法并不是主流虚拟机管理内存的方式。
- 可达性分析法:
- 定义:选择某些对象作为GC Roots,从GC Roots向下搜索,搜索走过的路径称为引用链,若GC Roots和某对象之间没有引用链,即GC Roots到这个对象不可达,则证明该对象不再被使用,这种对象也叫垃圾。
- 可作为GC Roots的对象:
- 虚拟机栈中引用的对象
- 本地方法栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 线程Thread对象
- 监视器对象,用来保存同步锁synchronized关键字持有的对象
- 虚拟机内部的一些特殊对象,比如基本类的类对象和一些常驻的异常对象,如OutOfMemoryError。
- 优点:可达性分析法实现简单,判断效率高,且有效解决引用计数法存在的对象之间循环引用问题。
(2)分类
JVM垃圾回收分为Minor GC和Full GC。Minor GC是只收集新生代的垃圾的GC。Full GC是收集整个堆的垃圾的GC,包括新生代、老年代、永久代(JDK1.8之后,永久代被替换为元空间metaspace,元空间由于位于直接内存,最大内存仅受系统内存限制(默认),但可以通过设置参数来调整元空间内存大小,一旦metaspace满了,也会触发Full GC)。
(3)GC触发场景
A、当Eden区满的时候,会触发Minor GC。
B、FullGC触发的场景:
- 老年代空间不足;
- 从新生代移动到老年代的对象过大;
- 永久代(或者元空间)空间不足;
- 手动调用System.gc()方法;
- 由于空间分配担保原则引起的Full GC;
空间分配担保原则的定义:
空间分配担保原则是JVM提供的一个用来保证对象能够进入老年代的机制。
该原则内容是:在Minor GC之前,JVM会先判断老年代的最大可用连续空间是否能够容纳新生代所有对象。若足够,则继续进行Minor GC。否则,JVM会判断-XX:HandlePromotionFailure参数,该参数表示是否允许担保失败,若允许担保失败,JVM会继续判断老年代的最大可用连续空间是否大于历次晋升到老年代的平均大小,若大于则继续进行Minor GC,尽快这次Minor GC有风险失败。但是若小于或者不允许担保失败,JVM则会进行一次Full GC。
允许担保失败且进行MinorGC后,可能出现的3种情况:
- MinorGC后,新时代存活对象(未到年龄)大小小于survior区,则成功复制到survior区;
- Minor GC后,新时代存活对象大小大于survior区,且这批对象大小小于老年代的最大可用连续空间,则成功复制到老年代;
- MinorGC后,新时代存活对象大小大于老年代最大可用连续空间,则会触发Full GC,若FullGC后,老年代依然没有足够的空间,此时就会发生OOM错误。
(4)垃圾收集算法
A、什么是垃圾收集算法
垃圾收集算法是JVM进行垃圾回收的策略。
B、垃圾收集算法的种类
(5)垃圾收集器
A、什么是垃圾收集器
垃圾收集器是JVM提供的自动管理内存分配和回收的机制。