jvm是java虚拟机吧,深入理解java虚拟机
如何解决写爬虫IP受阻的问题?立即使用。
以这张图为例。从。java到。类是一个编译过程,从。类到机器代码是一个解释过程。以下分别优化。在优化过程中,编译阶段的优化主要是前端编译器的优化,运行阶段的优化主要是即时编译器的优化。
编译器优化
编译过程
以上是javac的编译流程图,以下是javac编译流程的主要代码。
下面详细解释了这些步骤。
1.分析并填写符号表。
词汇分析
把源代码的字符流变成一组Token,Token是编译过程中最小的元素,比如a,=,b,int。
语法分析
根据标记序列构建抽象语法树。以后编译器基本不会对源文件进行操作,后续操作都是基于抽象语法树。抽象语法树是一种用来描述程序代码语法结构的树表示。节点表示代码中的语法结构,如修饰符、返回值等。
填充符号表
符号表是由一组符号地址和符号信息组成的表,用于编译的不同阶段。比如在语义分析中,用于语义检查,生成中间代码;在目标代码生成阶段,它被用作地址分配的基础。
2、注解处理器
其中一部分是插件注释处理器在编译期间处理注释的过程。它可以修改语法树。一旦它被修改,编译器将返回到上面的第一步进行重新处理。每个循环称为一轮,就是上图中的循环过程。
3、语义分析与字节码生成
经过语法分析,生成的语法树是源程序的抽象,结构正确,但不能保证源程序是逻辑的。语义分析的任务是检查结构正确的源程序的上下文敏感性质。例如,下面代码中的错误只能在语义分析阶段检测到。
布尔a=假;
char b=2;
Int c=a b这个阶段包括以下四个步骤:
标注检查
变量在使用前是否已经声明,变量和赋值之间的数据类型是否可以匹配等。还有一种是常数折叠,就是把a=1 2换成a=3。因此,代码中的a=1 2和a=3不会增加程序运行时cpu指令的计算量。
数据及控制流分析
检查程序的局部变量在使用前是否赋值,方法的每个路径是否有返回值,所有检查到的异常是否处理正确。在类加载期间还有一个数据和控制流分析。其目的基本相同,只是验证的范围不同。有些验证项只能在编译时或运行时运行。
解语法糖
语法是在计算机语言中加入一些语法,对语言的功能没有影响,但可以提高程序的可读性。语法包括泛型、自动解包等。虚拟机在运行时不支持这些语法,它们在编译时被还原为基本语法结构。这个过程叫做解析糖。
字节码生成
将前面步骤生成的信息(语法树,符号表)转换成字节码写入磁盘,然后添加并转换少量代码。例如,用StringBuffer或StringBuilder的append()操作替换string的加法操作。
此时,生成了类文件。
语法糖
Sugar是java中加入的一种语法,对语言的功能没有影响,但是可以增加程序的可读性。包括泛型、内部类、枚举类等。
1.泛型和类型擦除
泛型可用于创建类、接口和方法,并用于约束放置在集合中的元素的类型。泛型只存在于程序的源代码中,在编译阶段就有解决语法糖的步骤,所以在。类文件。这个过程被称为类型擦除。
通用擦除前:
公共静态void main(String[] args){
MapString,String map=new HashMap();
Map.put (name ,晓明);
Map.put(性别,男性);
sout(map . get( name ));
Sout(map.get(性别));
}清除泛型后:
公共静态void main(String[] args){
map map=new HashMap();
Map.put (name ,晓明);
Map.put(性别,男性);
Sout(字符串)地图。
sout((String)map . get( gender ));
}所以ArrayList和ArrayList在运行时是同一个类。
2.盒子的自动拆装和循环遍历。
这些是java中使用最多的语法糖。编译前:
公共静态void main(String[] args){
list integer list=arrays . as list(1,2,3,4);
int sum=0;
for(int i:list){
sum=I;
}
system . out . println(sum);
}编译后:
公共静态void main(String[] args){
list list=arrays . aslist(new Integer[]{
Integer.valueOf(1),
Integer.valueOf(2),
Integer.valueOf(3),
integer . value of(4)});
int sum=0;
for(Iterator local Iterator=list . Iterator();local iterator . has next();){
int I=((Integer)local iterator . next())。int value();
sum=I;
}
system . out . println(sum);
}可以看到,自动反汇编框在编译后被转换成相应的打包和还原方法,比如Integer.valueOf()和Integer.intValue()。
循环将代码还原到迭代器的实现。
3.条件编译
根据真、假布尔常数值,编译器会剔除分支中的无效代码块。
公共静态void main(String[] args){
如果(真){
sout(“第一街区”);
}否则{
sout(“第二街区”);
}
}编译后,代码变成:
公共静态void main(String[] args){
sout(“第一街区”);
}运行期优化
一般我们编译。java成。类,然后解释。类转换成机器码。但也有特殊情况。有些代码调用频繁,比如某个方法或者代码块运行非常频繁。为了提高程序的执行效率,虚拟机在运行时直接将这段代码编译成机器码,并在各个层面进行优化。这种代码被称为热点代码。完成这项任务的编译器被称为实时编译器。但它不是虚拟机的必要部分。
实时编译器概述
(1)为什么虚拟机要使用解释器和编译器并存的架构?
虚拟机包含解释器和编译器。当程序需要快速启动和执行时,解释器可以先发挥作用,节省编译和立即执行的时间。程序运行后,随着时间的推移,编译器逐渐发挥作用,将越来越多的代码编译成本地代码后,可以达到更高的执行效率。
当程序运行环境中的内存资源有限时,我们可以使用解释来节省内存,反之,我们可以使用编译来提高效率。
(2)为什么虚拟机要实现两个不同的即时编译器?
虚拟机内置了两个实时编译器,即客户端编译器和服务器编译器,也称为C1和C2。
默认情况下只使用其中一个。至于选择哪一个,要看虚拟机根据自身版本和主机硬件性能自动选择运行模式。用户也可以使用"-客户端"和"-服务器"来指定。
(3)程序何时使用解释器执行?何时使用编译器执行?
虚拟机具有分层编译策略。
0级:解释并执行程序,解释程序可以触发1级编译,而无需启动性能监控功能。
第1层:也称为C1编译,它将字节码编译成本地代码,进行简单可靠的优化,如果需要,还可以添加性能监控的逻辑。
第二层:也称为C2编译,它将字节码编译成本地代码,但会启用一些需要很长时间编译的优化,甚至基于性能监控信息做出一些不可靠的激进优化。
(4)哪些程序代码会被编译为本地代码?如何编译为本地代码?
热代码包括以下两类,都是以整个方法为编译对象。
一个被多次调用的方法
b,多次执行的循环体
热点检测用于判断一段代码是否是热点代码,有两种方式:
一、基于抽样调查
b、基于计数器。热点用这个。它为每个方法准备了两种计数器:方法调用计数器,计算方法被调用的次数;反向计数器,计算循环代码在方法中被执行的次数。
(5)如何从外部观察及时编译器的编译过程和编译结果?
可以使用-xx: PrintCompilation来查看即时编译器编译了哪些方法。
优化技术有哪些?
当虚拟机的实时编译器生成代码时,它采用以下代码优化技术。
(1)公共子表达式消除
如果一个表达式E已经计算过了,那么如果E再次出现就不会再计算了。例如:
Int=(a * b) * 12c (CB * a)如果这段代码交给javac编译器,不会进行任何优化。如果将它提供给实时编译器,它将通过以下步骤进行优化:
第一步:消除常见的子表达式。
Int=e * 12c (c e)第二步:代数化简:
int d=E*13 c*2(2)数组边界检查消除
什么是数组边界检查?
如果有一个数组foo[],在java语言中访问数组元素foo[i]时,系统会自动检查上下界的范围,检查I是否满足条件0 i 0ifoo.length
那怎么消除呢?
一、把运行时检查提到编译时完成。比如foo[3],只要编译时根据数据流分析确定foo.length的值,并且下标“3”没有越界,执行时就不需要判断。
b、隐式异常处理。这种思想通常用于除数为零时的空指针检查和运算符运算。
如果(foo!=null){
返回foo.value
}否则{
抛出新的NullPointException();
}经过隐式异常处理优化后,变成如下代码:
尝试{
返回foo.value
}catch(segment_fault){
uncommon _ trap();
}除了数组边界检查消除,还有自动装箱消除、安全点消除、反射消除等。
(3)方法内联
将目标方法的代码“复制”到调用方法中,以避免实际的方法调用。
public int add(int x1,int x2,int x3,int x4) {
返回add1(x1,x2) add1(x3,x4);
}
public int add1(int x1,int x2) {
返回x1 x2
}运行一段时间后,JVM会移除add1方法,将代码翻译成:
public int add(int x1,int x2,int x3,int x4) {
返回x1 x2 x3 x4
}(4)逃逸分析
当一个对象定义在一个方法中时,它可能被外部方法引用,比如作为调用参数传递给其他方法,这叫做方法转义。类似地,如果被外部线程访问,则称为线程转义。
变量的对应分析称为逃逸分析。如果可以证明其他方法或线程无法以任何方式访问这个对象,可以对这个变量进行一些优化。
优化方法包括栈上分配、同步消除、标量替换等。以同步消除为例。如果转义分析可以确定某个变量不会从线程中转义,即不能被其他线程访问,那么就可以消除对这个变量实现的同步措施。
以上内容都是关于JAVA虚拟机中的JVM优化。更多相关问题请访问PHP中文网:JAVA视频教程。以上是JAVA虚拟机(JVM)的详细介绍(七)。——JVM优化的细节。请多关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。