Java编译期与运行期优化探究

news2024/12/26 10:37:53

一:  即时编译器优化技术一览 



1.编译器策略(compiler tactics)
延迟编译(delayed compilation)
分层编译(tiered compilation)
栈上替换(on-stack replacement)
延迟优化(delayed reoptimization)
静态单赋值表示(static single assignment representation)


2.基于性能监控的优化技术(profile-based techniques)
乐观空值断言(optimistic nullnuess assertions)
乐观类型断言(optimistic type assertions)
乐观类型增强(optimistic type strengthening)
乐观数组长度增强(optimistic array length strengthening)
裁剪未被选择的分支(untaken branch pruning)
乐观的多态内联(optimistic N-morphic inlining)
分支频率预测(branch frequency prediction)
调用频率预测(call frequency prediction)


3.基于证据的优化技术(proof-based techniques)
精确类型推断(exact type inference)
内存值推断(memory value inference)
内存值跟踪(memory value tracking)
常量折叠(constant folding)
重组(reassociation)
操作符退化(operator strength reduction)
空值检查消除(null check elimination)
类型检测退化(type test strength reduction)
类型检测消除(type test climination)
代数简化(algebraic simplification)
公共子表达式消除(common subexpression elimination)


4.数据流敏感重写(flow-sensitive rewrites)
条件常量传播(conditional constant propagation)
基于流承载的类型缩减转换(flow-carried type narrowing)
无用代码消除(dead code elimination)


5.语言相关的优化技术(language-specific techniques)
类型继承关系分析(class hicrarchy analysis)
去虚拟化(devirtualization)
符号常量传播(symbolic constant propagation)
自动装箱消除(autobox elimination)
逃逸分析(escape analysis)
锁消除(lock elision)
锁膨胀(lock coarsening)
消除反射(de-reflection)


6.内存及代码位置变换(memory and placement transformation)
表达式提升(expression hoisting)
表达式下沉(expression sinking)
冗余存储消除(redundant store elimination)
相邻存储合并(adjacent store fusion)
交汇点分离(merge-point splitting)


7.循环变换(loop transformations)
循环展开(loop unrolling)
循环剥离(loop peeling)
安全点消除(safepoint elimination)
迭代范围分离(iteration range splitting)
范围检查消除(range check elimination)
循环向量化(loop vectorization)


8.全局代码调整(global code shaping)
内联(inlining)
全局代码外提(global code motion)
基于热度的代码布局(heat-based code layout)
Switch调整(switch balancing)


9.控制流图变换(control flow graph transformation)
本地代码编排(local code scheduling)
本地代码封包(local code bundling)
延迟槽填充(delay slot filling)
着色图寄存器分配(graph-coloring register allocation)
线性扫描寄存器分配(linear scan register allocation)
复写聚合(copy coalescing)
常量分裂(constant splitting)
复写移除(copy removal)
地址模式匹配(address mode matching)
指令窥空优化(instruction peepholing)
基于确定有限状态机的代码生成(DFA-based code generator)


第二:   Java语言的"编译期" 浅析

Java语言的“编译期”是一段不确定的过程,因为它可能指的是前端编译器把java文件转变成class字节码文件的过程,也可能指的是虚拟机后端运行期间编译器(JIT)把字节码转变成机器码的过程。 


编译期优化指的是javac编译器将java文件转化为字节码的过程,而运行期间优化指的是JIT编译器所做的优化


编译期优化:


虚拟机设计团队把对性能的优化集中到了后端的即时编译器(JIT)中,这样可以让那些不是由javac编译器产生的class文件也同样能享受到编译器优化所带来的好处。但是javac做了许多针对编码过程的优化措施来改善程序员的编码风格和提高编码效率。许多新生的java语法特性,都是靠编译器的“语法糖”来实现,而不是依赖虚拟机的底层改进来支持。所以说,java中即时编译器在运行期间的优化过程对于程序的运行来说更重要,而前端编译器在编译期的优化过程对于程序编码来说关系更加密切。

javac编译器的编译过程大致可分为三个步骤:

1.解析与填充符号表过程;

2.插入式注解处理器的注解处理过程;

3.语义分析与字节码生成过程。

下面分别来介绍。

解析与填充符号表;

解析步骤包含了词法分析和语法分析两个过程,首先词法分析是将源代码的字符流转变成为标记集合(token),然后语法分析是根据token序列来构造抽象语法树(一种用来描述程序代码语法结构的树状表示方式)。完成词法分析和语法分析之后,下一步是填充符号表,符号表是由一组符号地址和符号信息构成的表格,符号表中所登记的信息在编译的不同阶段都要用到(比如语义分析中符号表所登记的内容将用于语义检查和产生中间代码,目标代码生成阶段当对符号名进行地址分配时,符号表是地址分配的依据)。

插入式注解处理器的注解处理过程:

插入式注解处理器可以看做是一组编译器的插件,在这些插件里面,可以读取、修改、添加抽象语法树中的任意元素。如果这些插件在处理注解期间对语法树进行了修改,那么编译器将 回到解析及填充符号表的过程重新处理,直到所有的插入式注解处理器都没有再对语法树进行修改为止。

语义分析与字节码生成过程:

语法分析之后,编译器获得了程序代码的抽象语法树表示,语法树能够表示结构正确的源程序的抽象,但是无法保证源程序是否符合逻辑,而语义分析主要是对结构上正确的源程序进行上下文有关性质的检查。

1.标注检查

    标注检查步骤检查的内容包括诸如变量使用前是否已被声明、变量与赋值之间的数据类型是否能够匹配,等等。还有一个重要的动作称为常量折叠也在此阶段完成。

2.数据及控制流分析

      数据及控制流分析是对程序上下文逻辑更进一步的验证,它可以检查出诸如程序局部变量在使用前是否有赋值、方法的每条路径是否有返回值、是否所有的受查异常都被正确处理了等问题。

3.解语法糖

        语法糖是指在计算机语言中添加某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。java中的泛型,变长参数,自动拆箱与装箱,条件编译等就属于语法糖,它们在编译阶段就被还原成简单的语法结构(比如List<String>和List<Integer>在运行期间其实是同一个类)。

4.字节码生成

此过程是javac编译过程的最后一个阶段,字节码生成阶段将之前各个步骤所生成的信息转化成字节码写到磁盘中,另外还进行少量的代码添加和转换工作。


 

运行期优化:


在部分商用虚拟机中,java程序最初是通过解释器进行解释执行的,当虚拟机发现某个方法或代码块运行特别频繁,就会把这些代码认定为“热点代码”,为了提高热点代码的执行效率,在运行时,虚拟机就会把这些代码编译成与本地平台 相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器或JIT编译器。

即时编译器并不是虚拟机必须的部分,但是即时编译器编译性能的好坏、代码优化程度的高低确是衡量一款商用虚拟机优秀与否的最关键的指标之一。

众多主流的虚拟机都同时包含解释器和JIT编译器,解释器与JIT编译器各有优势:当程序需要迅速启动和执行时,解释器可以首先发挥作用,省去编译的时间,立即执行。当程序运行后,随着事件的推移,JIT编译器逐渐发挥作用,把越来越多的代码编译成本地代码之后,可以获取更高的执行效率。

 



     


 


会被即时编译器编译的热点代码有两类:


1.被多次调用的方法体;

2.被多次调用的循环体。

即时编译器会以整个方法作为编译对象,将其编译成机器码。这种编译方式因为编译发生在方法执行过程之中,因此被称作栈上替换(OSR)。

判断一段代码是否是热点代码的方式(热点探测)有两种:

1.基于采样的热点探测:

此方法会周期性检查各个线程的栈顶,如果发现某个或某些方法经常出现在栈顶,那么这个方法就是热点方法。此方法的缺点是很难精确地确认一个方法的热度,容易受到诸如线程阻塞等因素影响。

2.基于计数器的热点探测:

此方法会为每个方法甚至是代码块建立计数器,统计方法的执行次数,如果执行次数超过一个阀值就认为它是热点方法。

注:默认设置下,执行引擎并不会同步等待编译请求完成,而是继续进入解释器按照解释方式执行字节码,直到提交的请求被编译器编译完成。当编译工作完成之后,这个方法的调用入口地址就会被系统自动改写成新的地址,下一次调用该方法时就会使用已编译的版本。也就是说,在编译器还未完成之前,执行引擎仍按照解释方式继续执行,而编译动作则在后台的编译线程中进行。

优化技术:

一般来说即时编译器所产生的本地代码会比javac产生的字节码更优秀。即时编译器采用了一系列的技术来优化代码,比如公共子表达式消除,数组范围内检查消除,方法内联,逃逸分析等。

 


小案例一:


Java编译器的两点优化:
1.对于short\byte\char三种类型,如果右侧赋值的数值没有超过范围,那么javac编译器将会自动隐含地为我们补上一个(short)(byte)(char)。如果超过了范围,编译器会自动报错。

2.在给变量进行赋值的时候,如果右侧的表达式中全都是常量,没有任何变量,那么编译器javac将会直接计算若干个常量表达式,得到结果。例如:short result = 3+5;编译之后得到的.class字节码文件中直接就是:short result = 13;右侧的常量结果数值没有超过左侧范围,所以正确。这称为“编译器的常量优化”。但是,一旦表达式中有变量参与,就不能进行这种优化了。


 

用volatile关键字防止变量被编译器优化


浅析Java关键字volatile:


一,什么是volatile关键字,作用是什么


​ volatile是java虚拟机提供的轻量级同步机制

​ 作用是:

    1.保证可见性

    2.禁止指令重排

    3.不保证原子性


二,什么是JMM



​ JMM(java 内存模型 Java Memory Model 简称JMM) 本身是一个抽象的概念,并不在内存中真实存在的,它描述的是一组规范或者规则,通过这组规范定义了程序中各个变量(实例字段,静态字段和构成数组对象的元素)的访问方式.

JMM的同步规定:
​ 1.线程解锁之前,必须把共享变量刷新回主存

​ 2.线程加锁锁之前,必须读取主存的最新值到自己的工作空间

​ 3.加锁解锁必须是 同一把锁

​ 由于 JMM运行程序的实体是线程.而每个线程创建时JMM都会为其创建一个自己的工作内存(栈空间),工作内存是每个线程的私有 数据区域.而java内存模型中规定所有的变量都存储在主内存中,主内存是共享内存区域,所有线程都可以访问,但线程的变量的操作(读取赋值等)必须在自己的工作内存中去进行,首先要 将变量从主存拷贝到自己的工作内存中,然后对变量进行操作,操作完成后再将变量操作完后的新值写回主内存,不能直接操作主内存的变量,各个线程的工作内存中存储着主内存的变量拷贝的副本,因IC不同的线程间无法访问对方的工作内存,线程间的通信必须在主内存来完成, 其简要访问过程如下图:


               

 

三,可见性



​ 可见性:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

​ 通过前面的 JMM介绍,我们知道各个线程对主内存的变量的操作都是各个线程各自拷贝到自己的工作内存中进行操作,然后在写回主内存中

​ 这就可能存在一个线程a修改了共享变量X的值但还未写回主内存,又有一个线程b对共享变量X进行操作,但 此时线程a的工作内存的共享变量X对线程吧来说是不可见的,这种工作内存与主内存同步延迟的问题就造成了可见性问题


四,不保证原子性



​ 原子性:某个线程在执行某项业务时,中间不可被加塞或分割,需要整体完整。要么同时成功,要么同时失败

五,禁止指令重排

​ 计算机在执行程序时,为了提高性能,编译器和处理 器常常会对指令做重排,一般分为一下三种:

单线程的环境里指令重排确保最终执行的结果和代码顺序执行的结果一致,处理器在进行指令重排是必须 ,要考虑指令之间的数据依赖性;多线程的环境交替执行,由于编译器优化重排的存在,俩个线程使用变量能否保证一致性是无法确定的,无法预料的


主内存与工作内存 :

线程是 通过主内存 去进行线程间的 隐式通信 的,而线程对共享变量的写操作在 工作内存 中完成,由JMM控制 共享变量由工作内存写回到主内存的时机 。

JMM提供了一个保证内存可见性的原则: happens-before原则 。这个原则可以保证线程对共享变量的写操作对其它线程可见。如果在多线程环境下需要满足happens-before原则,就必须对共享变量添加某种特定的读写规则,否则会导致多线程环境下对共享变量的操作无法对其它线程可见,造成 缓存不一致 的现象。
 


                                            线程工作内存与主内存交互


              

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/807025.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电脑选睡眠、休眠还是关机?

关机 这是大家最熟悉的。关机时&#xff0c;系统首先关闭所有运行中的程序&#xff0c;然后关闭系统后台服务。随后&#xff0c;系统向主板请求关机&#xff0c;主板断开电源的供电使能&#xff0c;让电源切断对绝大多数设备的供电&#xff08;只剩一些内部零件仍会维持电源供应…

(20)(20.4) 飞行前测试控制装置

文章目录 20.4 飞行前测试控制装置 20.5 测试失控保护 20.6 减少控制的滞后性 20.4 飞行前测试控制装置 在第一次飞行之前&#xff0c;你应该测试所有的功能是否工作良好。 要检查上述控制措施的移动方向是否正确&#xff1a; 在操纵杆设置屏幕上单击"启用"按钮…

手机卡商家套路有哪些?我说的这几种你肯定遇到过!

大家好&#xff0c;我是51物联卡葫芦妹&#xff0c;我忍不住了&#xff0c;今天要给大家曝光几种常见的手机卡宣传骗术。 其实是这样的&#xff0c;昨晚有个粉丝问我&#xff0c;他私信我说让我帮他看看某个卡靠不靠谱&#xff0c;名曰超神卡&#xff0c;月租69块钱&#xff0…

多线程之GCD应用

一些套话 GCD全称是Grand Central Dispatch&#xff0c;它是纯 C 语言&#xff0c;并且提供了非常多强大的函数 GCD的优势&#xff1a; GCD 是苹果公司为多核的并行运算提出的解决方案GCD 会自动利用更多的CPU内核&#xff08;比如双核、四核&#xff09;GCD 会自动管理线程的…

Vue输入内容/链接生成二维码

方式一&#xff1a;qrcode&#xff08;无 icon 图标&#xff09; npm i qrcodejs2 --save完整代码 <template><div class"flex-box"><div>qrcode&#xff08;无 icon 图标&#xff09;</div><div class"qr-code" ref"qrCo…

MySQL Windows版本下载及安装时默认路径的修改

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、MySQL 下载二、默认路径修改1、安装前准备【非常重要】2、启动安装程序总结1、MySQL下载2、MySQL默认路径修改前言 MySQL 被Oracle收购后,各种操作规范及约束也相应的跟着来了,这不,只…

Linux服务器增加虚拟交换内存

文章目录 swap分区的创建1、查看磁盘使用情况2、添加Swap分区3、对交换文件格式化并转换为swap分区4、挂载并激活分区5、查看新swap分区是否正常添加并激活使用6、修改 fstab 配置&#xff0c;设置开机自动挂载该分区7、查看是否已经使用了交换内存 更改Swap配置查看当前的swap…

浅谈自动化测试

谈谈那些实习测试工程师应该掌握的基础知识&#xff08;一&#xff09;_什么时候才能变强的博客-CSDN博客https://blog.csdn.net/qq_17496235/article/details/131839453谈谈那些实习测试工程师应该掌握的基础知识&#xff08;二&#xff09;_什么时候才能变强的博客-CSDN博客h…

linux 指令最后一期

bc ---- linux下的计算器 bc 是一个计算器 我们输入&#xff1a;quit 来退出这个计算器 我们可以这样来用&#xff1a; uname -r uname –r指令&#xff1a; 语法&#xff1a;uname [选项] 功能&#xff1a; uname用来获取电脑和操作系统的相关信息。 补充说明&#xff1a…

springboot框架下,请使用@ConfigurationProperties替代@Value加载配置

一、背景 程序启动时&#xff0c;详细报错见下&#xff1a; 10:40:31.965 [main] ERROR org.springframework.boot.SpringApplication - Application run failed org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘redisDi…

【设计模式——学习笔记】23种设计模式——外观模式Facade(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入介绍基本介绍类图出场角色 案例实现案例一类图代码实现 案例二类图代码实现 外观模式在Mybatis源码中的应用总结文章说明 案例引入 在家庭影院中&#xff0c;要享受一场电影&#xff0c;需要如下步骤&#xff1a; 直接用遥控器&#xff1a;统筹各设备开关开…

De Bruijin序列与魔术(一)——De Bruijin序列简介

早点关注我&#xff0c;精彩不错过&#xff01; 欢迎回到数学魔术系列&#xff01;久违了&#xff01; 在牌序领域&#xff0c;一个特别数学化也是很冷门的一个序&#xff0c;DeBruijin序列&#xff0c;算是经典中的经典了。但它在魔术圈里流传并不甚广的原因是&#xff0c;可扩…

再创佳绩!数据猿荣获《2023金融科技影响力品牌》奖

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 7月26日至27日&#xff0c;CFS2023第十二届财经峰会暨2023可持续商业大会在北京举行&#xff0c;峰会期间举行了开幕式、高层论坛、CFS致敬盛典、2023品牌创新展等主题活动&#xff0c;以及多场关于数字化转型、金融创新、新…

一分钟搞定谷歌浏览器无法翻译的问题

文章目录 前言一、找到hosts.xml文件二、以记事本方式打开hosts文件三、在hosts文件最下方加入以下内容&#xff0c;点击保存&#xff1a;四、刷新DNS五、关闭google浏览器重新打开即可。 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 据CSDN消息&…

【Java 高频面试闯关秘籍】大梦谁先觉,平生我自知

一、mysql使用innodb引擎&#xff0c;请简述mysql索引的最左前缀如何优化orderby语句&#xff1f; 关键点&#xff1a; &#xff08;1&#xff09;如果排序字段不在索引列上&#xff0c;filesort有两种算法&#xff1a;mysql就要启动双路排序和单路排序 &#xff08;2&#x…

Diffusion Model 浅学笔记

Diffusion Model Created by: 银晗 张 Created time: May 29, 2023 8:12 AM VAE → GAN →Diffusion 要讲扩散模型&#xff0c;不得不提VAE。VAE和GAN一样&#xff0c;都是从隐变量Z生成目标数据X。 它们假设隐变量服从某种常见的概率分布&#xff08;比如正态分布&#xff…

Android Unit Test

一、测试基础知识 1.1 测试级别 测试金字塔&#xff08;如图 2 所示&#xff09;说明了应用应如何包含三类测试&#xff08;即小型、中型和大型测试&#xff09;&#xff1a; 小型测试是指单元测试&#xff0c;用于验证应用的行为&#xff0c;一次验证一个类。 中型测试是指…

ROS中使用Kinect v2

ROS中使用Kinect v2 Kinect v2 简介 Kinect v2是微软公司推出的第二代Kinect深度摄像头&#xff0c;也称为Kinect for Xbox One或Kinect for Windows v2。它是Kinect系列产品的升级版本&#xff0c;于2013年首次发布。Kinect v2采用了一系列先进的传感器和技术&#xff0c;使其…

【MATLAB第60期】【更新中】基于MATLAB的ARMAX具有外生回归因子的移动平均自回归模型

【MATLAB第60期】【更新中】基于MATLAB的ARMAX具有外生回归因子的移动平均自回归模型 版本更新&#xff1a; 2023/7/29版本&#xff1a; 1.增加自定义参数&#xff0c;方便直接套数据运行。 pre_num3;%预采样数据个数 learn_pr0.85; %训练数据比例&#xff08;不包括预采样数…

通讯录--集合动态的文件版

简易的通讯录往往需要朴实的“烹饪”就能完成一道“美味的佳肴”。 我们需要一个通讯录&#xff0c;能够存储联系人的信息&#xff0c;能够对联系人的信息进行增删查改&#xff0c;查询&#xff0c;按姓名排序。相比对之前的三子棋、扫雷&#xff0c;有了一定的了解&#xff0c…