JVM学习总结四:执行引擎(☆)

四、执行引擎(☆)

1.执行引擎概述

java是半编译半解释型语言
1.作用

将字节码指令解释/编译为对应平台上的本地机器指令。(因为本地机器指令无法识别字节码指令)

2.结构
  1. 解释器
    (java代码->java字节码)->c++代码->机器码
  2. 即时编译器(JIT-(Just In Time))
    java字节码->机器码
  3. GC
    在这里插入图片描述
3.执行过程
  1. 首先通过程序计数器找到执行的字节码指令
  2. 通过虚拟机栈栈帧中的 局部变量中找到堆空间中的对象实例数据
  3. 通过对象中的类型指针找到方法区类元信息

2.java代码的编译和执行的过程

1.java代码编译和执行的过程

在这里插入图片描述

  1. 橙色部分:前端编译,编译器将java源文件编译为字节码文件
  2. 绿色部分:解释器将字节码文件解释成本地的机器指令,并逐行执行
  3. 蓝色部分:JIT(即时编译器)将字节码指令编译为本地机器指令,但是不执行(解释热点代码,热点代码放在方法区中),内部有模板编译器。
2.为什么java是半编译半解释语言

在这里插入图片描述

1.原因

前端编译(javac),后端执行

编译指的是javac编译生成的字节码文件.class,但为什么是半呢,是因为生成的这个.class文件操作系统不能直接执行,需要解释器进行解释后(机器码),才可能运行,所以才把java叫做半编译半解释型语言。

2.什么是编译型语言,什么是解释型语言?
  • 编译型语言:编写好程序以后,首先需要编译器进行编译,统一转化成机器码,然后这个编译完的文件,可以放在操作系统直接执行
  • 解释型语言: 程序是边运行边进行机器码转化(转化完后cpu执)
3.什么是模板解释器、字节码解释器(前提都是直接读取的.class文件)
  • 字节码解释器:读取字节码,转换为c++代码,再由c++代码转换为硬编码,以此类推。其字节码解释器主要的缺点是执行比较慢(Java字节码->c++代码->硬编码);
  • 模板解释器 (JIT的一部分):刚开始的运行原理和字节码解释器一样,只不过模板解释器里面有个特殊的机制-即时编译(即时编译底层原理):
    1、申请一块内存:可读可写可执行(mac系统不支持,所以说mac系统不支持jit)
    2、将处理new字节码的硬编码拿过来
    3、将处理new字节码的硬编码写入申请的内存
    4、申请一个函数指针,用这个函数指针执行这块内存
    5、调用的时候,直接通过这个函数指针调用就可以了(Java字节码->硬编码)
4.执行引擎执行字节码的3种方式
  • -Xint 纯字节码解释器(1)
  • -Xcomp 纯模板解释器(2)
  • -Xmixed 字节码解释器 + 模板解释器(3)

注: VM默认是混合模式,我们可以执行下java -version查看下,可以通过java -Xint version来设置JVM的运行模式为纯字节码解释器。上面三个中执行模式中性能排比是什么呢,321或者是231,直接影响2和3的性能因素是,程序的大小。如果是大程序的话,可以直接采用混合模式,启动时间较快,编译优化器可以根据热点代码等进行优化。

在这里插入图片描述

5.即时编译器(JIT,即时编译器生成的代码就是给模板解释器用的)

HotSpot虚拟机内置了两个即时编译器,分别称为Client Compiler和Server Compiler,习惯上将前者称为C1,后者称为C2。

  • C1
    • 需要收集的较少
    • 编译优化比较浅
  • C2
    • 触发条件比较严格,一般来说,程序运行了一段时间以后才会触发
    • 优化比较深(优化汇编指令
    • 编译生成的代码执行效率较C1更高
  • 混合编译
    • 程序运行初期触发C1编译器
    • 程序运行一段时间后触发C2编译器
    • Client 编译器模式下,N 默认的值 1500(N表示热点代码的次数)
    • Server 编译器模式下,N 默认的值则是 10000
6.即时编译触发的条件:热点代码(存放在方法区)

在程序运行期间,根据对热点字节码的探测(运行次数超过某个阀值的代码),将这部分热点代码进行特别的优化,将其直接编译为本地机器码执行并缓存。其使用的 定期清理算法是LRU,最近最久未使用算法

7.LRU算法(缓存淘汰算法)

//TODO待补充

8.即时编译器是如何运行的呢?
  • 将即时编译任务(即函数弹出栈的次数)写入一个队列中;
  • VM_THREAD 读取任务,并运行

注:所以即时编译是一个异步的操作

9.基于逃逸分析,JVM开发了三种优化技术
  • 栈上分配:逃逸分析如果是开启的,栈上分配就是存在的(不发生gc的情况下,查看堆上的对象个数,如果是程序中创建的个数,就存在栈上分配)
    • -XX:+DoEscapeAnalysis 开启逃逸分析
    • -XX:-DoEscapeAnalysis 关闭逃逸分析
    • -XX:+PrintEscapeAnalysis 显示逃逸分析结果
  • 标量替换:标量:不可再分,java中的基本类型就是标量
public class ScalarSubstitution {
    public static void main(String[] ars) {
        Point point = new Point();
        System.out.println(point.x); //编译器会替换成System.out.println(0);
        System.out.println(point.y); //同上
    }
}

@Data
class Point {
    public int x;
    public int y;
}

  • 锁消除
public void test(){
    synchronized (new Object()){ //编译器判定这个对象是个局部变量,是线程私有的,所以就没必要加锁,会直接把锁去掉
        System.out.println("zong");
    }
}

3.解释器

1. 为什么需要字节码文件

可以实现跨语言,使其他的语言生成自己码指令,JVM也能执行。

2.解释器作用:

根据程序计数器的指令地址,逐条将字节码指令“翻译”为本地机器指令,以便程序能够运行。

4.即时编译器(JIT)

将整个函数体编译成机器码(当该函数执行次数达到一定次数的时候触发,变为热点代码),每次函数执行时,只编译机器码即可,还可以将常用的机器码进行缓存在方法区(元空间)中,从而提高效率。

5.解释器与即时编译器的优缺点

1.解释器:

优点:程序一开始执行的时候,解释器就能够逐条执行,省去编译的时间。

缺点:相对于即时编译器而言,逐条进行翻译效率较低

2.即时编译器(JIT)

优点:因为是提前编译好的机器指令,因此效率更高;

缺点:程序一开始执行的时候,需要事先对字节码指令进行编译,需要一定的时间。

综上:HotSpot虚拟机采用两者兼容的方式,虚拟机开始启动后,解释器可以立即发挥作用,不需要等到即时编译器编译完后再去执行,节省不必要的编译时间,随着时间的推移,即时编译器编译完成之后,采用即时编译器效率更高。

6.StringTable(字符串)

1.String基本特性
  1. 存储结构的变更
    jdk1.8时采用char[] 进行存储;jdk1.9之后采用byte[] 进行存储;
  2. 不可变特性
    通过字面量的方式给一个字符串赋值,此时的字符串位于堆空间的常量池中,

  1. 字符串常量池中不会存储相同的字符串
    常量池中的字符串均是唯一的,如果两个字符串变量相等,则两个变量指向字符串常量池中的同一个地址。
    String Pool(常量池) 底层是一个固定大小的HashTable,默认长度为1009,可通过-XX:StringTableSize设置
2.String内存分配
  1. jdk1.6时,字符串常量池位于永久代内
  2. jdk1.7之后,字符串常量池位于堆空间;

移动的原因/好处:

永久代几乎不进行来及回收将其移动到堆空间后,更方便进行垃圾回收

3.详解见String笔记
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值