Java编译优化你真的读懂了吗?15个问题考验一下自己


首先提出一个问题,为什么C++的编译速度会比java慢很多?二者运行程序的速度差异子啊那? 了解了java的早期和晚期过程,就能理解这个问题了。

这里会提15个问题确认是否真的理解,如果完全没这方面的概念,则好好看一下前面的早期和晚期编译优化读书笔记

早期编译过程


Q: java早期编译过程分为哪3步?
A:

  1. 词法语法解析、填充符号表
  2. 注解处理
  3. 语义分析与字节码生成。

Q: 上面的步骤中, 符号表是干吗的?
A:
符号表是符号地址和符号信息构成的表格。

  • 用于后面阶段做语法检查时,从表里取出信息进行对比。
  • 符号表是目标代码生成时的地址分配的依据

Q: 注解处理器做的什么事情?
A: 注解处理器会扫描抽象语法树中带注解的元素, 并进行语法树的更新。
重点就是他是基于语法树做更新。
更新之后我们会重新走回解析与填充的过程,重新处理。


Q: 上面的3个步骤中, 解语法糖是哪一步?
A:
是第三步,在生成字节码的时候才做的语法糖处理。


Q: 什么是解语法糖?大概有哪些?
A:

  • 虚拟机本身不支持这种语法, 但是会在编译阶段 把这些语法糖转为 普通的语法结构。
  • 包含自动装拆箱、 泛型强转应用。

Q: 生成字节码class文件的时候, final和非final的局部变量, 会有区别不?
A:
没有区别。
局部变量不会在常量池中持有符号引用, 所以不会有acesses_flasg信息。
** 因此final局部变量在运行期没有任何作用, 只会在编译期去校验。**


Q: a= 1 + 2会在什么阶段进行优化?
A: 会在早期编译过程的语义分析过程中,进行常量折叠, 变成a=3
同理, 字符串+号优化成stringBuilder.append()这个动作也是该阶段优化的。


Q: 类对象加载的过程有一堆顺序(具体见类初始化顺序, 这个顺序在字节码中体现的吗?还是运行的时候再判断顺序?
A:
字节码中体现的。

  • 在字节码生成时, 编译器针对对象new的过程,会生成了一个方法,里面写明了成员、构造方法的调用顺序。
  • 类静态成员的调用顺序同理封装在中。

晚期编译优化

Q:
早期编译优化和晚期编译优化的区别?
A:

  • 早期编译优化, 是把 java文件转成字节码,转字节码的过程中做一些简单优化和语法糖处理。
  • 晚期编译优化,是将字节码转机器码执行的过程中,结合一些信息进行动态优化,或者应用上很多的机器码优化措施。

Q: java程序运行的时候,是直接全部转成优化后的机器码再运行吗?
A:
错误。

  • 当程序刚启动时,会先马上使用解释器发挥作用,这时候没做太多优化,直接解释执行。
  • 在程序运行后, 编译器逐步发挥作用,把还没用到的代码逐步编译成机器码。

注意这里的编译器和之前提到的编译器的区别,一个是编译成字节码,另一个是编译成机器码。


Q: 有两种晚期优化编译器

  • Client Compiler ——C1编译器
  • Server Compiler——C2编译器
    他们二者的区别是什么?

A:

  • 速度和质量的区别:
    C1编译器, 更高的编译速度,编译质量一般。
    C2编译器, 更好的编译质量,但是速度慢。
  • 优化特性的区别
    C1编译器都是一些不需要运行期信息就能做优化的操作。
    C2编译器则会根据解释器提供的监控信息,进行激进且动态的优化

Q: java中怎么区分用C1还是C2?
A:
关于这2种编译器的参数:

  • -Xint参数: 强制使用解释模式
  • -Xcomp参数: 强制使用编译模式( 但是如果编译无法进行时, 解释会介入)
  • 选择编译模式时,有-client、-server还有MixedMode(混合模式)可以选择

混合模式中, JDK7引入了分层编译策略:
第0层: 解释执行。 不开启性能监控。
第1层: C1编译, 把字节码编译为本地代码, 进行一些简单优化, 加入性能监控
第2层: C2编译, 启动耗时较长的优化, 根据性能监控信息进行激进优化


Q: 分层优化中,如果正在运行,jvm是怎么知道需要对哪些代码做JIT或者OSR优化?
A:

  1. 被多次调用的方法。 会触发JIT编译(热点代码计数器)
  2. 被多次执行的循环体, 会触发OSR编译(栈上替换), 发生在方法执行过程中, 所以是在栈上编译并切换方法。(使用回边计数器)

Q: 哪些方法会在早期优化中做内联,哪些方法会在晚期优化中做内联?
A:

  • 不能被继承重写的方法,比如私有、构造器、静态之类的方法,可以直接在早期优化中做内联优化。
  • 其他会被抽象继承实现的方法在早期无法做内联,因为他不知道实际是用哪一段代码.
  • 晚期优化中可以根据一些运行信息,判断是否总是只用某个子类方法跑,是的话做一下尝试内联,如果后面来了其他的子类就切回去。

Q: java数组一般都会自动做边界检查,不满足就抛异常。 什么情况下会优化掉这个自动检查?
A:
运行期,发现传入的参数放到数组中用的时候, 肯定不会超出边界,则会优化掉这个检查动作。


看完上面的,就可以给出C++和java编译和运行速度差距的原因了:

  1. java即时编译可能会影响用户体验,如果在运行中出现较大影响的延迟的话。
  2. java中虚方法比C++要多, 因为做各种内联分析消耗的检查和优化的就越多越大
  3. java中总是要做安全检查, C++中不做,出错了我就直接崩溃了越界了
  4. C++中内存释放让用户控制, 无需后台弄一个垃圾回收器总是去检查和操作
  5. java好处: 即时编译能够以运行期的性能监控进行优化,这个是C++无法做到的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值