分层编译器有哪些层次?分层编译根据编译器编译、优化的规模和耗时 , 划分不同的编译层次 , 包括:
- 第0层:程序解释执行 , 解释器不开启性能监控功能 , 可出发第1层编译 。
- 第1层:也成为C1编译 , 将字节码编译为本地代码 , 进行简单可靠的优化 , 如有必要加入性能监控的逻辑 。
- 第2层:也成为C2编译 , 也是将字节码编译为本地代码 , 但是会启用一些编译耗时较长的优化 , 甚至会根据性能监控信息进行一些不可靠的激进优化 。
编译对象与触发条件热点代码有哪些?
- 被多次调用的方法
- 被多次执行的循环体
- 基于采样的热点探测 , 虚拟机周期性检查各个线程的栈顶 , 如果发现某个方法经常出现在栈顶 , 那这个方法就是“热点方法” 。实现简单高效 , 但是很难精确确认一个方法的热度 。
- 基于计数器的热点探测 , 虚拟机会为每个方法建立计数器 , 统计方法的执行次数 , 如果执行次数超过一定的阈值 , 就认为它是热点方法 。
- 方法调用计数器
- 回边计数器(判断循环代码)
有哪些经典的优化技术(即时编译器)?
- 语言无关的经典优化技术之一:公共子表达式消除
- 语言相关的经典优化技术之一:数组范围检查消除
- 最重要的优化技术之一:方法内联
- 最前沿的优化技术之一:逃逸分析
如果一个表达式E已经被计算过了 , 并且从先前的计算到现在E中所有变量的值都没有发生变化 , 那么E的这次出现就成了公共子表达式 。没有必要重新计算 , 直接用结果代替E就可以了 。数组边界检查消除因为Java会自动检查数组越界 , 每次数组元素的读写都带有一次隐含的条件判定操作 , 对于拥有大量数组访问的程序代码 , 这无疑是一种性能负担 。
如果数组访问发生在循环之中 , 并且使用循环变量来进行数组访问 , 如果编译器只要通过数据流分析就可以判定循环变量的取值范围永远在数组区间内 , 那么整个循环中就可以把数组的上下界检查消除掉 , 可以节省很多次的条件判断操作 。
方法内联内联消除了方法调用的成本 , 还为其他优化手段建立良好的基础 。
编译器在进行内联时 , 如果是非虚方法 , 那么直接内联 。如果遇到虚方法 , 则会查询当前程序下是否有多个目标版本可供选择 , 如果查询结果只有一个版本 , 那么也可以内联 , 不过这种内联属于激进优化 , 需要预留一个逃生门(Guard条件不成立时的Slow Path) , 称为守护内联 。
经验总结扩展阅读
- 2023年9月15日适合入宅吗 2023年9月15日入宅黄道吉日
- 2023年农历八月初一宜祭祖吗 2023年9月15日祭祖黄道吉日
- JVM学习笔记——垃圾回收篇
- 2023年1月27日取蜂蜜行吗 2023年1月27日适合取蜂蜜吗
- 2023年农历正月初六安装房门吉日 2023年1月27日是安装房门的黄道吉日吗
- 2023年1月27日举办成人仪式行吗 2023年1月27日举办成人仪式吉日一览表
- 银手镯变黑是生病了吗?
- 九州缥缈录铁皇结局是什么?
- 向前是什么电视剧的男主角?
- 长脸型适合什么样的眼镜?