Android安全交流群:478084054
从Android 7.0之后,JIT编译器被再次使用,并采用AOT/JIT混合编译的策略,特点:
* 在安装时,不会再调用dex2oat对DEX进行AOT编译。
* 在运行时,DEX先由解释器执行,并由JIT对热点函数进行实时编译。
* JIT编译后的结果会保存在JitCodeCache中,但不会被持久化,应用退出之后就不存在了。
* JIT除了即时编译之外,还有一个使命就是将热点函数信息记录到Profile。
* 当系统处于IDLE+充电状态时,会进行Profile-guided compilation。
即:基于Profile的AOT,由“AOT compilation (dex2oat) daemon”完成。
AOT compilation daemon的核心逻辑:
这样的话,AOT只编译热点函数,会节省存储空间。安装时不做AOT,可以加快安装速度。
JIT和AOT使用相同的编译器,所进行的一系列优化也较为相似,但生成的代码可能略有不同。因为:“JIT makes use of runtime type information, can do better inlining, and makes on stack replacement (OSR) compilation possible”。
因为JIT生成的代码相对更优,所以JIT和AOT代码共存时,首选JIT代码。既然有了AOT代码,为什么还会再JIT?官方文档举了一个例子:“e.g. due to repeated de-optimizations”。可能是JIT觉得AOT代码不够优化,需要进一步优化。
“Profile-guided compilation”只在“DEVICE IDLE & CHARGING”时进行,但可通过如下命令进行强制编译(我在测试加固包的兼容性的时候,才知道可以这么干):
Profile-based:
adb shell cmd package compile -m speed-profile -f my-package
Full:
adb shell cmd package compile -m speed -f my-package
还可通过如下命令,开启JIT日志:
adb root
adb shell stop
adb shell setprop dalvik.vm.extra-opts -verbose:jit
adb shell start
再来看一下JIT工作流:
最后,JIT是在ART启动时创建的:
从代码注释中也能看到,这里创建的JIT有两个作用,一个是JIT compilation,另一个就是save profiling info。后面会去读一些JIT的源码,加深对JIT的理解。
学习资料:
https://source.android.com/devices/tech/dalvik/jit-compiler