小白咨询大家一个问题,轻喷呀
1.JIT 会把部分热点代码直接编译成本机能够执行的机器码,那为什么不把所有的代码都直接在运行的时候编译成机器码呢?这样整个程序会更快些,由于内存吗?现在的机器内存都不太稀缺,对于服务端程序来说内存应该是可承受的吧 2.JIT 中把部分程序编译成机器码,部分不是,直接解释执行,请问两者之间有什么具体的区别,就算是解释执行的话机器应该也只是执行机器码吗?
真心求教
1
wwqgtxx 2018-08-14 17:48:03 +08:00 via iPhone
全部编译那就是 aot 了,主要还是编译消耗 cpu 资源,你看看 android5.0 那慢到窒息的 app 安装速度,到 android6.0 就改回 jit 了
另外一方面是 jit 可以分层优化,特别是可以边运行边优化,在代码运行到一定次数的时候,能动态把不必要的循环,递归都优化掉 解析执行的意思是一行一行的翻译执行,编译成机器码就是不在需要翻译了,当然最后执行的都是机器码 |
2
zjp 2018-08-14 17:57:54 +08:00 via Android
得看场景,JVM 分客户端模式和服务器模式。一般客户端在意启动速度,运行时间不长。可以假设一种极端情况,解析执行的执行完了,编译还没完成。
|
3
ekoeko 2018-08-14 18:02:39 +08:00
@wwqgtxx 请问,服务端更新应该不频繁,启动慢点无所谓吧,是不是可以把服务端的程序全部编译好再执行, 后面运行的效率会更高吧?这样会不会更好?
|
4
loqixh 2018-08-14 18:16:06 +08:00
策略不同而已 .net 就是方法第一次执行时编译成机器码, 不存在解释执行
|
5
aidoudou 2018-08-14 18:18:16 +08:00
个人理解:一般是采用并存的分层编译。热点代码要根据运行情况的性能监控来通过 JIT 优化;非热点代码,解释执行可以节约内存,并且没有通过 JIT 的必要。这其中应该有一个大致的平衡点(所以需要监控热点代码),单方面的全部 JIT 或者全部解释执行应该都不可取。
|
6
lovedebug 2018-08-14 18:22:18 +08:00 via Android
1. 很多代码只执行一次或很少执行,热编译反而代价大
2.JIT 要考虑到多线程同步问题和内存模型 |
7
ZSeptember 2018-08-14 18:31:28 +08:00 via Android
JIT 比较激进。如果发生 deoptimization 代价挺大的,所以不会全部 JIT。
|
8
lurenw 2018-08-14 18:31:51 +08:00
1. 在运行前编译叫做 AOT ( ahead-of-time ), 在运行前编译的好处是节省整个运行环节的时间,毕竟都是机器码了。缺点就是 AOT 不能根据运行时的状态做对应的优化,所以可能会做许多多余的优化
2. JIT 有个 PGO,在程序运行的时候采集信息(比如热点代码),然后可以做针对性的优化 3. 解释执行和编译执行到最后都是机器码。比如有些代码只跑一次,此时就没啥必要编译之后再跑,直接分析语法,最后转成机器码会快很多。 |
9
momocraft 2018-08-14 18:35:48 +08:00
JIT 编译不一定只发生一次 ,也不一定启动就能做(一些优化需要运行时信息)
|
10
luozic 2018-08-14 19:04:32 +08:00 via iPhone
可以手动指定编译方式。并且 hotspot 是 JiT 的一种方式,并不是所有的 JIT 使用这种方式实现
|
11
kaneg 2018-08-14 19:21:44 +08:00 via iPhone
很多代码在运行时才知道会不会执行到,举个极端的例子:classpath 有上百个 jar,但在 main 方法里只打印了 hello world 就结束了,这种情况下提前优化就没有意义。
|
12
cc128 2018-08-14 19:34:26 +08:00 via Android
编译的机器码体积要大很多。全部编译占用内存是一定的。jit 也会占用很多系统资源。而且 jit 是有一个阀值的。这里说的是 android,dalvok 和 art 的 jit 又不太一样。之前 android6.0 里 jit cache 是限制在 2m,6.0 没 release,7.0 又改了很多。结合了 aot+jit,并且把 jit 延迟到用户充电这种情况下。并且编译结果写入到一个文件。所以如果全部编译时间和空间都是一个大问题。还不如 aot。Aot 的话机器码是在磁盘上,是映射到内存。
编译出来的机器码是包含了虚拟机相关操作的。比如调用一个方法,并不是直接编译成 blx 或 call 指令。解释执行等于是查字典。每一条字节码指令对应一段虚拟机中行的代码。android 上是 switch case,goto 这种样子的。比如你调用函数,就会执行 INVOKE _VIRTUAL 的指令。 解释执行和机器码之间相互调用是通过汇编和 c 关联起来的。还涉及 manager stack 数据和 native stwck 数据的交换转移。 总的说细节还是很多。。。😁😁😁 |
13
LukeChien 2018-08-15 08:17:34 +08:00 via Android
可能是技术还不成熟,Java9 已经可以完全 JIT 编译成原生代码了
|