Java学习-程序编译与代码优化

介绍

java代码编译器代表性的有三类
前端编译器:我们熟知的javac就是前端编译器
JIT编译器:即时编译器,如hotspot的C1与C2编译器,java的大部分优化在这个编译器里
AOT编译器:这个是什么鬼?

程序编译

javac程序编译分为三个过程:解析与填充符号表的过程,插入式注解处理器的注解处理过程,分析与字节码生成过程。具体未去探究

语法糖

语法糖的定义
语法糖是在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是方便程序员使用。

1.java中的语法糖

1.1 泛型与泛型擦除

例如

 public static void method(List<String> list){
     System.out.println("测试");
 }
public static void method(List<Integer> list){
     System.out.println("测试");
 }

上述的这两个方法具有相同的方法签名,泛型擦除后都变成了

public static void method(List list){
    System.out.println("测试");  
}

所以如果最上面的两个方法在同一个文件.java文件中,将无法通过编译,但是如果有不同的返回参数会通过编译,这并不是说返回值属于方法的特征签名。能够共存的原因是.class文件只要是描述符不相同的两个方法就能共存。

1.2 自动装箱、拆箱、遍历循环

自动装箱,拆箱就不多说了。举下面例子

  Integer i=100;

这个代码将自动调用

Integer i = Integer.valueOf(100);

 Integer i = 10; //装箱 
 int t = i; //拆箱,实际上执行了 int t = i.intValue();

遍历循环
主要注意遍历循环需要被遍历的类实现Iterator接口。原因是在编译后
遍历循环把代码还原成了迭代器的实现。

1.3 条件编译

对于条件表达式中永远为false的语句,编译器将不对条件覆盖的代码段生成字节码。
例如

public static void main(String[] args){
    if(true){
        System.out.println("one");
    }else{
        System.out.println("two");
   }
}

这个代码编译后的class文件反编译的结果

public static void main(String[] args){
       System.out.println("one");
}

要注意的是只能使用条件为常量的if语句才能达到上述的效果

while(flase){
    System.out.print("www");
}

这个代码将无法完成编译

2 后期运行优化

2.1 解释器和即时编译器

当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译时间,随着时间的推移,即时编译器逐渐发挥作用,把越来越多的代码编译成本地代码,之后可以获得更高的执行效率。

2.2 JIT编译器编译对象及触发条件

编译对象:热点代码
哪些代码会成为热点代码?
1.被多次调用的方法体;
2.被多次调用的循环体。

如何确定代码成为热点代码?
1.基于采样的热点探测:
此方法会周期性检查各个线程的栈顶,如果发现某个或某些方法经常出现在栈顶,那么这个方法就是热点方法。此方法的缺点是很难精确地确认一个方法的热度,容易受到诸如线程阻塞等因素影响。

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

HotSpot 使用的是第二种-基于技术其的热点探测,并且有两类计数器:方法调用计数器(Invocation Counter )和回边计数器

2.3 编译过程

对于 Client 模式而言
它是一个简单快速的三段式编译器,主要关注点在于局部的优化,放弃了许多耗时较长的全局优化手段。
第一阶段,一个平台独立的前端将字节码构造成一种高级中间代码表示(High-Level Intermediate Representaion , HIR)。在此之前,编译器会在字节码上完成一部分基础优化,如 方法内联,常量传播等优化。

第二阶段,一个平台相关的后端从 HIR 中产生低级中间代码表示(Low-Level Intermediate Representation ,LIR),而在此之前会在 HIR 上完成另外一些优化,如空值检查消除,范围检查消除等,让HIR 更为高效。

第三阶段,在平台相关的后端使用线性扫描算法(Linear Scan Register Allocation)在 LIR 上分配寄存器,做窥孔(Peephole)优化,然后产生机器码

对于 Server Compiler 模式而言
它是专门面向服务端的典型应用,并为服务端的性能配置特别调整过的编译器,也是一个充分优化过的高级编译器,几乎能达到 GNU C++ 编译器使用-O2 参数时的优化强度,它会执行所有的经典的优化动作,如 无用代码消除(Dead Code Elimination)、循环展开(Loop Unrolling)、循环表达式外提(Loop Expression Hoisting)、消除公共子表达式(Common Subexpression Elimination)、常量传播(Constant Propagation)、基本块冲排序(Basic Block Reordering)等,还会实施一些与 Java 语言特性密切相关的优化技术,如范围检查消除(Range Check Elimination)、空值检查消除(Null Check Elimination ,不过并非所有的空值检查消除都是依赖编译器优化的,有一些是在代码运行过程中自动优化 了)等。另外,还可能根据解释器或Client Compiler 提供的性能监控信息,进行一些不稳定的激进优化,如 守护内联(Guarded Inlining)、分支频率预测(Branch Frequency Prediction)等。

Server Compiler 编译器可以充分利用某些处理器架构,如(RISC)上的大寄存器集合。从即时编译的角度来看, Server Compiler 无疑是比较缓慢的,但它的便以速度仍远远超过传统的静态优化编译器,而且它相对于 Client Compiler编译输出的代码质量有所提高,可以减少本地代码的执行时间,从而抵消了额外的编译时间开销,所以也有很多非服务端的应用选择使用 Server 模式的虚拟机运行。

2.4 编译优化技术

2.4.1 公共子表达式消除

如 int d=(cb)12+a +(a+bc)
变成 int d=e
12+a+(a+e),经过代数化简后int d=e13+a2

2.4.2 数组边界检查消除

在虚拟机的执行子系统中,每次数组元素的读写都带有一次隐含的条件判定操作。对于拥有大量数组访问的代码,这也是一种性能负担。无论如何,为了安全,数组的边界检查是必须要做的,但是数组边界检查是不是必须在运行期间一次不漏的检查则是可以“商量”的事情。
如foo[3] 只要在编译期根据数据流分析来确定foo.length的值,并判断下标3没有越界,执行的时候就不需要判断了。
还有如果编译器能通过数据流分析判定循环变量的取值范围永远在[0,foo.length)之间,那么整个循环就可以把数组的上下界检查消除。

2.4.3 方法内联

存在的问题
对于虚方法,编译期间无法确定使用方法的哪个版本
解决方案
类型继承关系分析(CHA)
如果是非虚方法,则直接进行内联即可。如果CHA查询出来的结果有多个版本的目标方法,则通过内联缓存做最后一次努力。
内联缓存工作原理
在未发生方法调用之前,内联缓存状态是空的,当第一次调用发生时,缓存记录下方法的接受者版本信息,并且每次运行方法调用都比较接受者的版本,如果一致,内联可以一致使用下去,如果发现不一致就要取消内联查找虚方法表进行方法分派。

2.4.4 逃逸分析(不成熟)

栈上分配,同步消除(锁消除),标量替换

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容