深入理解JVM之编译优化

JDK在源码编译阶段将源码编译为JVM字节码,JVM字节码是一种平台无关的中间代码方式,要由JVM在运行期间对其进行解释并执行,这种方式称为字节码解释执行方式。
对于面向对象的语言而言,最重要的是执行方法的指令,JVM有一套自己的执行方法的指令:invokestatic(调用static方法)、invokevirtual(调用对象实例的方法)、invokeinterface(调用接口的方法)、invokespecial(调用private方法和编译源码后生成的方法,此方法为对象实例化时的初始化方法)

字节码是在栈中执行
线程创建时,会产生程序计数器(PC)、栈,PC存放下一条要执行的指令在方法内的偏移量。栈中存放栈帧,栈帧主要分为局部变量区、操作数栈两部分。
局部变量区用于存放方法的局部变量和参数,操作数栈用于存放方法执行过程中产生的中间结果,栈帧中还有一些其它空间,如方法已解析的常量池引用。


图片发自简书App
void foo(){
    int a = 1;
    int b = 2;
    int c = (a + b) * 5;
}

编译后字节码:

code:
0:iconst_1 //将类型为int、值为1的常量放入操作数栈
1: istore_0 //将操作数栈中栈顶的值弹出放入局部变量区
2:iconst_2 //将类型为int、值为2的常量放入操作数栈
3:istore_1 //将操作数栈中栈顶的值弹出放入局部变量区
4:iload_0 //装载局部变量区中第一个值到操作数栈
5:iload_1 //装载局部变量区中第二个值到操作数栈
6:iadd //执行int类型的add指令,并将计算结果放入操作数栈
7:iconst_5 //将类型为int、值为5的常量放入操作数栈
8:imul //执行int类型的mul指令,并将计算结果放入操作数栈
9:istore_2 //将操作数栈中栈顶的值弹出并放入局部变量区
10:return //返回

编译执行
解释执行的效率较低,为提升代码的执行性能,JVM提供将字节码编译为机器码的支持,编译在运行时进行,通常称为JIT编译器,JVM在执行过程中对执行频率高的代码进行编译,对执行不频繁的代码则继续采用解释执行的方式。
编译执行有两种模式:client compiler(-client)和server compiler(-server)
client compiler又称为C1,较轻量级,只做少量性能开销比较高的优化,它占用内存少,适合桌面交互式应用,它的优化方式主要有:方法内联,去虚拟化,冗余削除等。
1,方法内联:在方法中需要调用其它方法,需要经历参数传递、返回值传递及跳转等,方法内联即把调用到的方法的指令直接植入到当前方法中
2,去虚拟化:在装载class之后,进行类层次的分析,如发现接口的方法只提供一个实现类,那么对于调用了此方法的代码,也可以进行方法内联。
3,冗余削除:在编译时,根据运行时状况进行代码折叠或削除。去掉不需要的代码指令。
Server compiler又称为C2,较为重量级,C2采用大量传统编译优化技巧,占用内存多,适用于服务器端应用。
“逃逸分析”是C2进行很多优化的基础,逃逸分析是指根据运行状况来判断方法中的变量是否会被外部读取,如不会则认为此变量是逃逸的,基于逃逸分析C2在编译时会做标量替换、栈上分配、同步削除等
1,标量替换:用标量替换聚合量,见代码:

Point point = new Point(1,2);
System.out.println("point.x="+point.x+"; point.y="+point.y);

当point对象在后面的执行过程中未用到时,经过编译后,代码会变成类似下面的结构:

int x = 1;
int y = 2;
System.out.println("point.x="+x+"; point.y="+y);

这种方式的好处是,如果创建的对象并未用到其中的全部变量,则可节省一定的内存,对于代码执行而言,由于无需去找对象的引用,也会更快一些。
2,栈上分配:如果上例中,point是逃逸的,那么C2会选择在栈上直接创建point对象实例,而不是在JVM堆上,在栈上分配的好处一方面是快速,另方面是垃圾回收时随着方法的结束,对象也就被回收了。
3,同步削除:指同步的对象逃逸,方法外部没有引用到同步的对象,那就没有同步的必要了,C2编译时会直接去掉同步。

JVM会根据机器配置来选择C1还是C2,当机器配置CPU达到2核且内存超过2G则选择C2,但是32位windows机器上始终选择C1模式,也可在启动时通过-client或-server来强制指定。
基于这个特性,在对java代码进行性能测试时,要注意是否实现做了足够次数的调用,以保证测试是公平的。对于高性能的程序而言,也应考虑在程序提供给用户访问前,自行进行一定的调用,以保证关键功能的性能。

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

推荐阅读更多精彩内容