JVM---执行引擎

 

概述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
     *  【执行引擎-概述】
     *      what?
     *          Execution Engine;
     *          执行引擎 是JVM核心的组成部分之一;
     *
     *          虚拟机与物理机的 执行引擎:
     *              同:
     *                  都有代码执行能力;
     *              异:
     *                  物理机:
     *                      执行引擎 直接建立在 处理器、缓存、指令集、OS 上的;
     *                  虚拟机:
     *                      执行引擎 由软件自行实现,不受物理条件制约地 定制指令集及执行引擎的结构体系,能够执行不被硬件直接支持的指令集格式;
     *
     *          JVM的主要任务是 负责装载字节码到JVM内部,但 字节码并不能直接运行在OS上;
     *              (字节码指令并非等价于本地机器指令,JVM内部的只是能被JVM识别的字节码指令、符号表、其他辅助信息...)
     *
     *      作用:
     *          将 字节码指令 解释/编译 为 对应平台的本地机器指令;
     *
     *      工作过程:
     *          执行引擎 在执行过程中 需要执行什么样的字节码指令 完全依赖于 PC寄存器;
     *          每当执行完一条字节码指令,PC寄存器 就会更新下一条需要被执行的 字节码指令地址;
     *          方法在执行过程中,执行引擎 可能会通过 存储在局部变量表中的对象引用 准确定位到 存储在堆区的对象实例信息;
     *                                  通过 对象头中的 元数据指针 定位到 目标对象的类型信息;
     */

  

Java代码编译和执行过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
     *  【执行引擎-Java代码编译和执行的过程】
     *      大部分的程序代码 转换成 物理机的目标代码(或虚拟机能执行的指令集)之前,都需要经过以下各个步骤:
     *
     *          程序源码 -> 词法分析 -> 单词流 -> 语法分析 -> 抽象语法树 -> 指令流(可选) -> 解释器 -> 解释执行
     *                          【javac实现】                                     【字节码解释器interpreter】
     *
     *                                                             -> 优选器(可选) -> 中间代码(可选) -> 生成器 -> 目标代码
     *                                                                            【JIT编译器】
     *
     *      解释器 interpreter:
     *          当JVM 启动时 会根据 预定义的规范 对字节码 采用逐行解释的方式执行;
     *              (将 每条字节码指令 翻译 为 对应平台的本地机器指令执行)
     *
     *      JIT编译器 Just In Time Compiler:
     *          JVM 将 源代码 直接编译成 对应平台的本地机器指令;
     *
     *      <机器指令->汇编语言->高级语言->字节码>
     *
     *          机器指令:
     *              what:
     *                  CPU能直接识别并执行的指令;
     *                      (二进制编码方式 表示)
     *
     *              组成:
     *                  操作码
     *                      指令的功能
     *                          (该指令要完成的操作)
     *
     *                  操作数
     *                      参与运算的对象
     *
     *              特点:
     *                  机器指令 与 CPU密切相关,不同种类的CPU对应的机器指令也不同;
     *
     *
     *              指令:
     *                  由于 机器指令是0和1 组成的二进制序列,可读性太差,于是人们发明了指令;
     *                  指令 就是 把机器码的0和1序列,简化为 对应的指令(mov,inc...),可读性稍好;
     *                  不同的硬件平台,执行同一个操作,对应的机器指令可能不同;
     *
     *
     *              指令集:
     *                  每个平台所支持的指令,称为 对应平台的指令集;
     *                      eg:
     *                      x86指令集,对应 x86架构的平台;
     *                      arm指令集,对应 arm架构的平台;
     *
     *          汇编语言:
     *              由于 机器指令 可读性太差,于是 发明了 汇编语言;
     *
     *              在汇编语言中,用 助记符代替机器指令的 操作码,
     *                          用地址符号或标号代替指令或操作数的地址;
     *
     *              特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植;
     *
     *              工作方式:
     *                  在不同的硬件平台中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令;
     *
     *
     *
     *          高级语言:
     *              一种 独立于机器,面向过程或对象的语言;
     *
     *              工作方式:
     *                  高级语言设计的程序必须经过 解释或编译 为 本地机器指令 以后才能被机器执行;
     *
     *              eg:
     *                  C、C++ 源程序执行过程经历2个阶段:
     *                          1、编译: 源代码 -> 汇编代码
     *                              读取 源程序,进行词法和语法分析,将高级语言指令转换为功能等效的汇编代码;
     *
     *                          2、汇编: 汇编代码 -> 本地机器指令
     *                              把 汇编代码 翻译成 本地机器指令;
     *
     *          字节码:
     *              what?
     *                  中间码;
     *                  二进制代码;
     *                  比 机器指令更抽象;
     *
     *              实现方式:
     *                  javac 将 Java源代码 编译为 字节码指令;
     *
     *              工作方式:
     *                  由 执行引擎 对字节码指令 进行 解释/编译 为对应平台的机器指令,交由CPU执行;
     */

  

执行方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
     *  【执行引擎-执行方式】
     *      设置执行引擎执行方式:
     *          当VM启动时,解释器首先发挥作用,不必等待JIT编译器全部编译完成再执行,这样可以省去很多不必要的编译时间;
     *
     *          并且随着程序运行时间的推移,JIT编译器逐渐发挥作用,根据热点探测功能,将有价值的字节码编译为本地机器指令,获得更高的执行效率;
     *
     *      设置执行引擎执行方式:
     *          默认Hotspot VM采用 解释器与JIT编译器 并存的架构;
     *
     *          自定义执行方式:
     *              -Xint:
     *                  完全采用 解释器模式 执行程序;
     *
     *              -Xcomp:
     *                  完全采用 JIT编译器模式 执行程序,如果JIT出现问题,解释器会介入执行;
     *
     *              -Xmixed:
     *                  采用 解释器+JIT编译器 混合模式 执行程序;
     *
     */

 

解释器  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
     *  【执行引擎-解释器 interpreter】
     *      工作方式:
     *          当JVM 启动时 会根据 预定义的规范 对字节码指令 采用逐行解释的方式执行;
     *              (将 每条字节码指令 翻译 为 对应平台的本地机器指令执行)
     *
     *      解释器分类:
     *          字节码解释器:
     *              (Java源码 -> 字节码) -> (C++代码 -> 本地机器指令)
     *                  javac                  执行引擎-字节码解释器
     *
     *          模板解释器:
     *
     */

  

即时编译器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
     *  【执行引擎-即时编译器 Just In Time Compiler】
     *
     *      what?
     *          前端编译器
     *              .java -> .class
     *              eg:javac
     *
     *          后端编译器
     *              字节码指令 -> 本地机器指令
     *              eg:Hotspot VM的C1、C2
     *
     *      JIT分类:
     *          Hotspot VM中,有2个JIT编译器:
     *              Client Compiler(C1编译器)、Server Compiler(C2编译器)
     *
     *      自定义使用某个JIT编译器:
     *              -client
     *
     *                  指定JVM在client模式下运行,并使用 C1编译器;
     *
     *                  C1编译器 对字节码 进行简单可靠的优化,耗时短;
     *
     *              -server
     *
     *                  (64位默认使用 Server模式)
     *                  指定JVM在server模式下运行,并使用 C1编译器;
     *
     *                  C2编译器 耗时较长的优化,以及激进优化;
     *
     *      C1编译器 和 C2编译器 不同优化策略:
     *              C1:
     *                  方法内联
     *                      将引用的函数代码编译到引用点处,这样可以减少栈桢的生成,减少参数传递以及跳转过程;
     *                  去虚拟化
     *                      对唯一的实现类进行内联;
     *                  冗余消除
     *                      在运行期间把一些不会执行的代码折叠掉
     *
     *              C2:
     *                  优化主要是在全局层面,逃逸分析是优化的基础;
     *                  基于逃逸分析的几种优化:
     *                      标量替换:
     *                          用标量值 代替聚合对象的属性值
     *                      栈上分配:
     *                          对于未逃逸对象分配在栈
     *                      同步消除:
     *                          清除同步操作,通常指synchronized
     *
     *      JIT编译器执行方式:
     *          将 JIT编译请求 放入队列中(VM_THREAD),由一个异步线程监听处理队列内容
     *
     */

  

分层编译

1
2
3
4
5
/**
     *  【执行引擎-JIT编译器-分层编译】
     *      Java 7开始引入了分层编译的概念;
     *      结合了C1和C2的优势,追求启动速度和峰值性能的一个平衡;
     */

  

热点代码及探测方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
     *  【执行引擎-JIT编译器-热点代码及探测方式】
     *          是否需要启动JIT编译器将字节码直接编译为本地机器指令,需要根据代码被调用执行的频率而定;
     *
     *          热点代码:
     *              需要被编译为本地机器指令的字节码;
     *
     *              JIT编译器 在运行时 会对 频繁被调用的热点代码做出深度优化,将其直接编译为本地机器指令,以提升Java程序执行性能;
     *
     *              ***哪些字节码是热点代码?
     *                  一个被调用多次的方法;
     *                  一个方法体内循环次数较多的循环体;
     *
     *              ***一个方法究竟被调用多少次(或一个循环体执行多少次循环)才能达到热点标准?
     *                  依靠热点探测功能;
     *
     *                  热点探测功能实现:
     *                      Hotspot VM采用 基于计数器的热点探测;
     *                          Hotspot VM为每个方法都建立2个不同类型的计数器:
     *                              a,方法调用计数器:
     *                                  统计方法调用次数
     *
     *                                  默认阈值 client模式 1500次,server模式 10000次
     *
     *                                  设置方法调用计数器阈值:
     *                                      -XX:CompileThreshold
     *
     *                                  <热度衰减>
     *                                      如果不做任何阈值设置,方法调用计数器统计的并不是方法被调用的次数,而是一个相对的执行频率(一段时间内方法被调用次数);
     *
     *                                      当超过一定的时间限度,如果方法的调用次数仍不足以让它提交给JIT编译器编译,那这个方法的调用计数器就被减少一半,这个过程称为方法调用计数器的热度衰减,这段时间称为方法统计的半衰周期;
     *
     *                                      热点衰减 是在虚拟机进行垃圾回收时顺便进行的;
     *
     *                                      关闭热点衰减:
     *                                          -XX:-UseCounterDecay
     *
     *                                          关闭后,只要系统运行时间足够长,绝大部分方法都被编译为本地机器指令;
     *
     *                                      设置半衰周期的时间:
     *                                          -XX:CounterHalfLifeTime ,单位秒
     *
     *                              b,回边计数器:
     *                                  统计循环体执行的循环次数
     *
     *          <热点代码缓存>
     *
     *              java -XX:+PrintFlagsFinal -version | grep CodeCache
     *
     *              位置:
     *                  方法区
     *
     *              默认大小:
     *                  server 2496KB起
     *                  client 160KB起
     *
     *              最大大小:
     *
     */

  

疑问

1
2
3
4
5
6
7
8
9
10
11
/**
     *  【疑问】
     *      1、为什么Java是半编译半解释型语言?
     *          a, Java源码 -> 字节码 (javac)
     *          b, 执行引擎 解释执行/编译执行 字节码
     *
     *      2、既然Hotspot VM中已经内置了JIT编译器了,为什么还需要性能低的解释器?
     *          当程序启动后,解释器可以马上发挥作用,省去编译时间,立即执行;
     *
     *          JIT编译器想发挥作用,需要把代码编译为本地机器指令,需要一定执行时间;
     */

  

 

方法调用计数器

 

posted on   anpeiyong  阅读(62)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2021-04-07 《计算机网络原理-西安交通大学》---网络体系结构
2020-04-07 asm
2020-04-07 cglib
2020-04-07 Javaassist

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示