V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cc959798
V2EX  ›  Java

关于 Java 中 JIT 的问题

  •  1
     
  •   cc959798 · 2018-08-14 17:38:01 +08:00 · 2718 次点击
    这是一个创建于 2300 天前的主题,其中的信息可能已经有所发展或是发生改变。

    小白咨询大家一个问题,轻喷呀

    1.JIT 会把部分热点代码直接编译成本机能够执行的机器码,那为什么不把所有的代码都直接在运行的时候编译成机器码呢?这样整个程序会更快些,由于内存吗?现在的机器内存都不太稀缺,对于服务端程序来说内存应该是可承受的吧 2.JIT 中把部分程序编译成机器码,部分不是,直接解释执行,请问两者之间有什么具体的区别,就算是解释执行的话机器应该也只是执行机器码吗?

    真心求教

    14 条回复    2018-08-15 12:13:07 +08:00
    wwqgtxx
        1
    wwqgtxx  
       2018-08-14 17:48:03 +08:00 via iPhone
    全部编译那就是 aot 了,主要还是编译消耗 cpu 资源,你看看 android5.0 那慢到窒息的 app 安装速度,到 android6.0 就改回 jit 了
    另外一方面是 jit 可以分层优化,特别是可以边运行边优化,在代码运行到一定次数的时候,能动态把不必要的循环,递归都优化掉

    解析执行的意思是一行一行的翻译执行,编译成机器码就是不在需要翻译了,当然最后执行的都是机器码
    zjp
        2
    zjp  
       2018-08-14 17:57:54 +08:00 via Android
    得看场景,JVM 分客户端模式和服务器模式。一般客户端在意启动速度,运行时间不长。可以假设一种极端情况,解析执行的执行完了,编译还没完成。
    ekoeko
        3
    ekoeko  
       2018-08-14 18:02:39 +08:00
    @wwqgtxx 请问,服务端更新应该不频繁,启动慢点无所谓吧,是不是可以把服务端的程序全部编译好再执行, 后面运行的效率会更高吧?这样会不会更好?
    loqixh
        4
    loqixh  
       2018-08-14 18:16:06 +08:00
    策略不同而已 .net 就是方法第一次执行时编译成机器码, 不存在解释执行
    aidoudou
        5
    aidoudou  
       2018-08-14 18:18:16 +08:00
    个人理解:一般是采用并存的分层编译。热点代码要根据运行情况的性能监控来通过 JIT 优化;非热点代码,解释执行可以节约内存,并且没有通过 JIT 的必要。这其中应该有一个大致的平衡点(所以需要监控热点代码),单方面的全部 JIT 或者全部解释执行应该都不可取。
    lovedebug
        6
    lovedebug  
       2018-08-14 18:22:18 +08:00 via Android
    1. 很多代码只执行一次或很少执行,热编译反而代价大
    2.JIT 要考虑到多线程同步问题和内存模型
    ZSeptember
        7
    ZSeptember  
       2018-08-14 18:31:28 +08:00 via Android
    JIT 比较激进。如果发生 deoptimization 代价挺大的,所以不会全部 JIT。
    lurenw
        8
    lurenw  
       2018-08-14 18:31:51 +08:00
    1. 在运行前编译叫做 AOT ( ahead-of-time ), 在运行前编译的好处是节省整个运行环节的时间,毕竟都是机器码了。缺点就是 AOT 不能根据运行时的状态做对应的优化,所以可能会做许多多余的优化
    2. JIT 有个 PGO,在程序运行的时候采集信息(比如热点代码),然后可以做针对性的优化
    3. 解释执行和编译执行到最后都是机器码。比如有些代码只跑一次,此时就没啥必要编译之后再跑,直接分析语法,最后转成机器码会快很多。
    momocraft
        9
    momocraft  
       2018-08-14 18:35:48 +08:00
    JIT 编译不一定只发生一次 ,也不一定启动就能做(一些优化需要运行时信息)
    luozic
        10
    luozic  
       2018-08-14 19:04:32 +08:00 via iPhone
    可以手动指定编译方式。并且 hotspot 是 JiT 的一种方式,并不是所有的 JIT 使用这种方式实现
    kaneg
        11
    kaneg  
       2018-08-14 19:21:44 +08:00 via iPhone
    很多代码在运行时才知道会不会执行到,举个极端的例子:classpath 有上百个 jar,但在 main 方法里只打印了 hello world 就结束了,这种情况下提前优化就没有意义。
    cc128
        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 数据的交换转移。

    总的说细节还是很多。。。😁😁😁
    LukeChien
        13
    LukeChien  
       2018-08-15 08:17:34 +08:00 via Android
    可能是技术还不成熟,Java9 已经可以完全 JIT 编译成原生代码了
    wwqgtxx
        14
    wwqgtxx  
       2018-08-15 12:13:07 +08:00
    @LukeChien 我记得并不可以完全编译,AOT 仅限于标准库
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1706 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:43 · PVG 00:43 · LAX 08:43 · JFK 11:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.