1.
Java
语言编译过程中比较有代表性的编译器:
1)
前端编译器:把
*.java
文件转变成
*.class
文件的过程,如
Sun
的
Javac
、
Eclipse JDT
中得增量式编译器。
2)
JIT
编译器:虚拟机的后端运行期编译器把字节码转化成机器码的过程,如
HotSpot VM
的
C1
、
C2
编译器。
3)
AOT
编译器:静态提前编译器直接把
*.java
文件编译成本地机器代码的过程,如
GUN Compiler for the Java
(
GCT
)、
Excelsior JET
。
2.
在部分的商用虚拟机(
Sun Hotspot
、
IBM J9
)中,
Java
程序最初是通过解释器进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁,就会把这些代码认定为“热点代码”,为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器。
3.
当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行。当程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码之后,可以获取更高的执行效率。当程序运行环境中内存资源限制较大,可以使用解释执行节约内存,反之可以使用编译执行来提升效率。
4.
Hotspot
虚拟机中内置了两个即时编译器,称为
Client Compiler
和
Server Compiler
,或者简称
C1
编译器和
C2
编译器。
5.
基于计数器的热点探测:采用这种方法的虚拟机会为每个方法建立计数器,统计方法的执行次数,如果执行次数超过一定的阀值就认为它是“热点方法”。
6.
在
HotSpot
虚拟机中使用的是基于计数器的热点探测方法,因此它为每个方法准备了两个计数器:方法调用计数器和回边计数器。
7.
方法调用计数器:用于统计方法别调用的次数,默认阀值在
Client
模式下是
1500
次,在
Server
模式下
10000
次,这个阀值可以通过虚拟机参数
-XX:CompileThreshold
来人工设定。
8.
当超过一定的时间限度,如果方法的调用次数仍然不足以让它提交给即时编译器编译,那这个方法的调用计数器就会减少一半,这个过程称为方法调用计数器的热度衰减,而这段时间就称为半衰周期,可以使用虚拟机参数
-XX:UseCounterDecay
来关闭热度衰减,另外可以使用
-XX:CounterHalfLifeTime
参数设置半衰周期的时间,单位是秒。
9.
回边计数器:用于统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令就称为“回边”。回边计数器没有计数热度衰减的过程,因此这个计数器统计的就是该方法循环执行的绝对次数。
10.
Client
Compiler
又称为
C1
,只做少量性能开销比高的优化,它占用内存较少,适合于桌面交互式应用。在寄存器分配策略上,
JDK6
以后采用的为线性扫描寄存器分配算法,在其他方面的优化主要有:方法内联、去虚拟化、冗余消除等。
1)
方法内联:对于
Java
类面向对象的语言,通常要调用多个方法来完成功能。执行时,要经历多次参数传递、返回值传递及跳转等,于是
C1
采取了方法内联的方式,即把调用到的方法的指令直接植入当前方法中。小于
-XX:MaxInlineSize=35
字节的函数指令直接植入
-XX:+PrintInlining
可以查看内联信息;如:
bar(){
small();
}
small(){
...Code;
}
->
bar(){
...Code;
}
2)
去虚拟化:去虚拟化是指在装载
class
文件后,进行类层次的分析,如发现类中的方法只提供一个实现类,那么对于调用了此方法的代码,也可进行方法内联,从而提升执行的性能。接口只有一个实现类时,直接植入实现方法指令;如:
execute(IFoo foo){foo.bar(Code)} ->execute(){Code}
3)
冗余消除:根据运行时状况进行代码折叠或消除,如:
if(true){Code}->Code
11.
Server
Compiler
又称为
C2
,
C2
采用了大量的传统编译优化技巧来进行优化,占用内存相对会多些,适合与服务器端的应用。寄存器分配策略上
C2
采用的为传统的图着色寄存器分配算法,由于
C2
会收集程序的运行信息,因此其优化的范围更多在于全局的优化。收集的信息主要有:分支的跳转
/
不跳转的频率、某条指令上出现过的类型、是否出现过空值、是否出现过异常。
1)
逃逸分析:当一个对象在方法里面被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他方法中,这种行为称为方法逃逸。甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,这种行为称为线程逃逸。用户可以使用参数
-XX:+DoEscapeAnalysis
来手动开启逃逸分析。
2)
栈上分配:如果确定一个对象不会逃逸出方法之外,那让这个对象在栈上分配内存将会是一个很不错的主意,对象所占用的内存空间就可以随栈帧出栈而销毁。
3)
同步消除:线程同步本身就是一个相对耗时的过程,如果逃逸分析能够确定一个变量不会逃逸出线程,无法被其他线程访问,那这个变量的读写肯定就不会有竞争,对这个变量实施的同步措施也就可以消除掉。
4)
标量替换:如果把一个
Java
对象拆散,根据程序访问的情况,将其使用到的成员变量恢复原始类型来访问就叫做标量替换。如果逃逸分析证明一个对象不会被外部访问,并且这个对象可以被拆散的话,那程序真正执行的时候将可能不创建这个对象,而改为直接创建它的若干个被这个方法使用到的成员变量来代替。
出了
C1
、
C2
外,还有一种较为特殊的编译为:
OSR
(
On Stack Replace
)。
OSR
编译和
C1
、
C2
最主要的不同点在于
OSR
编译只替换循环代码的入口,而
C1
、
C2
替换的是方法调用的入口,因此在
OSR
编译后会出现的现象是方法的整段代码被编译了,但只有在循环代码体部分才执行编译后的机器码,其他部分则仍然是解释执行方式。
分享到:
相关推荐
JVM学习笔记(一)--------基本结构 JVM学习笔记(二)----java代码编译和执行的整个过程 JVM学习笔记(三)---------内存管理和垃圾回收 JVM学习笔记(四)------内存调优
1.java开发环境--java编译运行过程(常见面试题) 2.名词解释--JVM;JRE,JDK 3.配置环境变量 4.eclipse: 开发环境 开发步骤 注释
Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行 《JVM必知必会》记录了对JVM的总结及学习笔记,详解...
主要介绍了JVM学习笔记第二篇,关于Java代码编译和执行的整个过程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
Java编译语言将Java代码编译成.class文件(只有一种形式),而C/C++语言将代码编译成01码,不同的操作系统的01码指令不同,这造成了不能跨平台,而Java将这个任务交给JVM,不同操作系统上的JVM将.class文件编译成不同...
java7 rt.jar源码 ...来依次编译每一行代码解释为本地机器指令; 后者是通过 寻找热点代码 进行即时编译为本地机器指令; GC: 垃圾回收器 主要的三款商用虚拟机JVM: 1) HotSpot JVM 特点: 热点代码探索
《Java JDK 7学习笔记》详细介绍了JVM、JRE、Java SE API、JDK与IDE之间的对应关系。必须要时从Java SE API的源代码分析,了解各种语法在Java SE API中如何应用。 《Java JDK 7学习笔记》将IDE操作纳为教学内容...
答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。 40.接口是否可...
Java虚拟机(Java Virtual Machine,简称JVM),Java的“一处编译,处处运行”,就是因为Java程序编译成字节码文件后可以在任何计算机的JVM上执行,所以JVM是我们学习Java的重点之一。 JVM = 类加载器(classloader) + ...
DOS操作 切换盘符: d: 进入文件夹:cd 文件夹名 命令提示: tab 一次性进入多个文件夹: cd\文件夹\文件夹 返回上级目录: cd … 进入当前目录: cd . ...java xx文件名(不要后缀) 运行编译后的java程序
springboot学习笔记 spring基础 Spring概述 Spring的简史 xml配置 注解配置 java配置 Spring概述 Spring的模块 核心容器CoreContainer Spring-Core Spring-Beans ...
JAVA语言跨平台执行,它必须先编译后解释执行,它能提供程序运行(JVM)的虚拟环境,使程序代码独立于平台 JAVA吸收C和C++的优点,基础语法与C语言模式完全一样,容易掌握 JAVA健壮性高,它去掉指针、内存申请和释放...
Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。...Scala 源代码被编译成Java字节码,所以它可以运行于JVM之上,并可以调用现有的Java类库。
程序代码经过编译之后转换成一种称为Java字节码的中间语言,Java虚拟机(JVM)将对字节码进行解释和运行。编译只进行一次,而解释在每次运行程序都会进行。编译后的字节码采用一种针对JVM优化过的机器码形式保存,...
它的设计目标是“一次编写,到处运行(Write Once, Run Anywhere)”,这意味着开发者可以使用Java编写应用程序,并在支持Java的任何平台上无需重新编译即可运行,这得益于其独特的跨平台性,通过Java虚拟机(JVM)...
它的设计目标是“一次编写,到处运行(Write Once, Run Anywhere)”,这意味着开发者可以使用Java编写应用程序,并在支持Java的任何平台上无需重新编译即可运行,这得益于其独特的跨平台性,通过Java虚拟机(JVM)...
Golang学习笔记(一):缘起及一个不一样的HelloWorld1 缘起2 安装go3 Hello World也是可以好好说道说道滴 :)3.1 编写hollo.go源代码3.2 hello.go代码说明3.3 执行程序3.4 编译程序4 结语 1 缘起 本人公司的项目后端...
类是使用javac程序编译的。 根据 Java 源文件的内容,编译会生成一个或多个类文件。 一个例子如下所示: javac TestClass . java 使用java程序执行 Java 类。 一个例子如下所示: java TestClass a b c Java 虚拟机 ...