java为什么是半编译半解释型语言
1、首先让我们先弄清楚什么是编译型语言,什么是解释型语言?
- 编译型语言:编写好程序以后,首先需要编译器进行编译,统一转化成机器码,然后这个编译完的文件,可以放在操作系统直接执行
- 解释型语言: 程序是边运行边进行机器码转化(转化完后cpu执)
引用“李白写代码”(【这就好像我们吃一袋瓜子,解释性语言是剥一颗吃一颗,直到吃完;而编译性语言是先把一袋瓜子全部剥完,剥出肉,然后一口吃进去。你说这两种模式对于最后吃的人来说,哪种会比较快,结果不言而知吧!】这里的一袋瓜子其实就是一段程序,吃瓜子的人就是操作系统。)
2、什么是模板解释器、字节码解释器(前提都是直接读取的.class文件)
- 字节码解释器:读取字节码,转换为c++代码,再由c++代码转换为硬编码,以此类推。其字节码解释器主要的缺点是执行比较慢(Java字节码->c++代码->硬编码);
-
模板解释器:刚开始的运行原理和字节码解释器一样,只不过模板解释器里面有个特殊的机制-即时编译(即时编译底层原理:1、申请一块内存:可读可写可执行
2、将处理new字节码的硬编码拿过来
3、将处理new字节码的硬编码写入申请的内存
4、申请一个函数指针,用这个函数指针执行这块内存
5、调用的时候,直接通过这个函数指针调用就可以了)
(Java字节码->硬编码)
3、模板解释器和字节码解释器的区别及其应用场景
-
由于模板解释器已经提前生成了字节码到硬编码的映射,当读取到一条字节码,只需要去一张映射表中,找到当前字节码对应的机器指令,这个时候,直接执行机器码。而字节码解释器,是读取到一条字节码,然后把其翻译成C++代码,然后再由C++代码生成机器指令,这样的执行过程较模板解释器来说,执行效率就没那么高。
补充:上面所说的模板解释器提前生成的字节码到硬编码的过程,其实是在程序启动的时候,生成的,如果当前项目较大的话,启动程序的时候,一定需要很长的时间,因为在启动的时候需要生成字节码到硬编码的映射,当然这样做的目的是,执行效率会更高。
4、JVM的三种运行模式
- -Xint 纯字节码解释器(1)
- -Xcomp 纯模板解释器(2)
-
-Xmixed 字节码解释器 + 模板解释器(3)
注:JVM默认是混合模式,我们可以执行下java -version查看下,可以通过java -Xint version来设置JVM的运行模式为纯字节码解释器。上面三个中执行模式中性能排比是什么呢,321或者是231,直接影响2和3的性能因素是,程序的大小。如果是大程序的话,可以直接采用混合模式,启动时间较快,编译优化器可以根据热点代码等进行优化。
基于上面的模板解释器运行模式,我们在现实生活中会遇到这样的问题,比如,在用解释器解释字节码时,有时候会出现,相同的代码会被执行多次,这样的话,就会导致,花费了很多时间,浪费了很多资源,当然,既然出现问题了,那就有相对应的解决方案,即时编译器诞生了,即时编译是一个动态编译的过程,即时编译器其实就是监测解释器执行的代码块,它会把代码块对应的执行次数记录下来,当执行次数很多的时候,就会优化对应的热点代码,并把对应的机器指令更新在映射表中,这样在下次执行到类似的代码块时,就可以直接运行更新了的的机器指令。接下来让我们再来看下即时编译器吧 ^ _ ^
5、即时编译器(JIT,即时编译器生成的代码就是给模板解释器用的)
HotSpot虚拟机内置了两个即时编译器,分别称为Client Compiler和Server Compiler,习惯上将前者称为C1,后者称为C2。
-
c1
1、触发的条件相对C2比较宽松:需要收集的数据较少
2、编译的优化比较浅:基本运算在编译的时候运算掉了
String s1 = "1"; String s2 = "2"; final String s3 = s1 + s2;//按理来说这一步应该会产生一个新的String对象,但是编译器判断是final类型,直接会将s1+s2替换为“12”
3、c1编译器编译生成的代码执行效率较C2低
-
c2
1、触发的条件比较严格,一般来说,程序运行了一段时间以后才会触发
2、优化比较深(优化汇编指令)
3、编译生成的代码执行效率较C1更高 -
混合编译
程序运行初期触发C1编译器
程序运行一段时间后触发C2编译器
Client 编译器模式下,N 默认的值 1500(N表示热点代码的次数)
Server 编译器模式下,N 默认的值则是 10000
6、即时编译触发的条件:热点代码(存放在方法区)
在程序运行期间,根据对热点字节码的探测(运行次数超过某个阀值的代码),将这部分热点代码进行特别的优化,将其直接编译为本地机器码执行并缓存。其使用的定期清理算法是LRU,最近最久未使用算法
java -client -XX:+PrintFlagsFinal -version | grep CICompilerCoun //查看当前执行即时编译的线程个数,intx CICompilerCount表示个数
7、即时编译器是如何运行的呢?
- 将即时编译任务(即函数弹出栈的次数)写入一个队列中;
-
VM_THREAD 读取任务,并运行
注:所以即时编译是一个异步的操作
8、即时编译的优化方式
- 逃逸分析:什么叫逃逸呢?逃逸就是这个对象的作用域不是局部的,逃逸的对象优化工作很困难。
9、基于逃逸分析,JVM开发了三种优化技术
- 栈上分配:逃逸分析如果是开启的,栈上分配就是存在的(不发生gc的情况下,查看堆上的对象个数,如果是程序中创建的个数,就存在栈上分配)
- 标量替换:标量:不可再分,java中的基本类型就是标量
import lombok.Data; 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"); } }
10、了解了上面的这些知识点以后,对于如果别人问你什么是半编译半解释型语言,知道该怎么回答了么?
编译指的是javac编译生成的字节码文件.class,但为什么是半呢,是因为生成的这个.class文件操作系统不能直接执行,需要解释器进行解释后,才可能运行,所以才把java叫做半编译半解释型语言。
本文地址:https://blog.csdn.net/Zong__Zong/article/details/108020997
上一篇: 爆囧,个个都是奇葩之星
推荐阅读
-
java为什么是半编译半解释型语言
-
PHP是解释型语言还是编译型语言
-
java为什么是半编译半解释型语言
-
PHP是解释型语言还是编译型语言
-
php是编译型语言还是解释型语言
-
脚本语言是必然趋势,在开发成本面前,其他都是浮云。现在的问题是,把解释语言转成编译语言的转换器,如Java的JIT compiler,你认为最近Facebook开源的JIT PHP编译器及虚拟机,是否可以提供这种可能性?
-
PHP是解释型语言还是编译型语言?
-
PHP 作为解释性语言,与编译型语言 Java,C++ 有性能差距,怎么提高 PHP 效率?
-
PHP 作为解释性语言,与编译型语言 Java,C++ 有性能差距,怎么提高 PHP 效率?
-
脚本语言是必然趋势,在开发成本面前,其他都是浮云。现在的问题是,把解释语言转成编译语言的转换器,如Java的JIT compiler,你认为最近Facebook开源的JIT PHP编译器及虚拟机,是否可以提供这种可能性?