android 基础-Dalvik ,ART,JIT,AOT,Dex,Odex

Dalvik 和 ART

Dalvik:Dalvik 虚拟机,android 5.0 以前所使用的虚拟机,可执行文件为 dex 格式,基于寄存器的虚拟机(jvm 基于堆栈)。通过 dx 工具将 .class 文件转换为 .dex 格式。

ART:android rutime,android 5.0 以后使用的虚拟机。

关于这个虚拟机的点,希望了解的关注点在于虚拟机这块。

ios 和 android对比,android 是基于虚拟机的,android 开发者使用 kotlin/java 编写代码(java 是编译-解释性语言),最终会编译成 .class 文件,.class 文件经过 dx 工具会优化成 dex 格式文件,dex 格式文件可以在虚拟机上执行。ios 开发者通过编写 Objective-C 或者 Swift 语言,是直接编译为机器码的。基于这点,ios 原生要比 android 存在优势。

但是随着编译技术的发展,两者的性能差距越来越小,甚至基本持平。

Dex 文件

java 代码通过 java 编译器生产 .class 文件,.class 文件在通过 dx 工具,生产 dex 文件。dex 格式的详细说明如链接:dex 文件格式

JIT

JIT:Just In Time Compiler 及时编译技术。关注这个及时编译的含义。android 系统上, dex 文件 并不直接在系统层面执行的, davlik 负责解释 dex,并且生成操作系统可以执行的微指令。

jit 存在的缺陷:

  1. 每次启动都需要重新编译
  2. 运行时耗电量大

AOT

JIT 是即时编译,是动态编译,可以对执行次数频繁的 dex 代码进行编译和优化,减少使用时的编译时间,虽然可以提高执行性能,但是本身编译需要耗费时间。Google 在 5.0 之后使用 ART 替代 Dalvik,包括了 AOT 的使用。

AOT 是静态编译。应用安装过程中,会使用 dex2oat 工具,把 dex 预编译成 ELF 文件,每次运行过程不用重新编译。

android 编译过程的发展

android 2.2

早期的android 支持 jit 编译,通过 JIT 优化编译。但是显然存在问题

  • 每次启动之后,都要进行 JIT 编译
  • 如果执行没有进行 JIT 编译的代码,还是得不到优化效果

具体的 JIT 的流程,参考 android 7.0 的说明。

android 5.0

5.0 以后,google 使用了 新的 ART 虚拟机,在 ART 虚拟机上,使用 AOT 把字节码dex/odex 优化成可执行的字节码 ELF 文件。可是这样也会带来新的问题。

  • 每次 app 升级,都要重新进行 OAT 操作
  • 每次系统升级 也要进行 OAT 操作
  • OAT 操作需要额外的存储空间

android 7.0

android 7.0 之后,google 醒悟了,使用了AOT + JIT 的混合编译模式;具体策略如下:

  • app 首次安装,dex 不会通过 AOT 优化
  • app 运行期间,dex 文件通过解析器被直接执行,热点函数会被识别,并且被 JIT 编译后存在 JIT Code Cache,并且生成 profile 文件以记录热点函数的信息
  • 手机进入空闲状态,系统会扫描 appp 目录下的 profile 文件, 并且执行 AOT 过程

这样就能够避免了首次安装的等待,同时进行代码优化。
具体的 profile 文件的逻辑,参考我后面的文章。

ART 包括一个编译器工具(dex2oat工具),dex2oat 会根据 dex 文件生成一个或者多个编译工具文件,具体的可能有不同版本差异,在 android O版本下,有以下文件:

  • .vdex :包含了 APK 未压缩的 DEX 代码,以及一些加快验证速度的元数据
  • .odex:包括了经过 AOT 编译优化的代码
  • .art:包含了 APK 中累出字符串和类的 ART 内部表示,用于加快启动速度

ART 进行编译结构如下图

jit-workflow.png
  1. 用户运行应用,此举随后触发 ART 加载.dex 文件。
    • 如果有 .oat 文件(即 .dex 文件的 AOT 二进制文件),ART 会直接使用该文件。虽然 .oat 文件会定期生成,但文件中不一定会包含经过编译的代码(即 AOT 二进制文件)。
    • 如果 .oat 文件不含经过编译的代码,ART 会通过 JIT 和解释器执行 .dex 文件。
  2. 针对任何未根据 speed 编译过滤器编译的应用启用 JIT(也就是说,要尽可能多地编译应用中的代码)。
  3. 将 JIT 配置文件数据转储到只有该应用可以访问的系统目录下的文件中。
  4. AOT 编译 (dex2oat) 守护程序通过解析该文件来推进其编译。

android 8.0

android 8.0 改进优化解释器速度。

android 9.0

android 9.0 之后,改进模板代码,简单来说,就是同样的代码,不同的编译模板生产的机器码不一样,android 在 9.0 优化了 vm 模板。

但是 vm 模板没有针对 不同 app 进行优化。

Dex2oat

Dex2oat 是 ART 里面的一个编译工具;

ART 的编译选项,分为两种类型:

  1. 系统 ROM 配置:编译系统映像时,会对哪些代码进行 AOT 编译
  2. 运行时配置:ART 如何在设备上编译和允许应用

编译配置,也就是传递给 dex2oat 存在四个参数:

  1. verify:只运行 DEX 代码验证
  2. quicken:运行 DEX 代码验证,并优化一些 DEX 指令,以获得更好的编译器性能
  3. speed: 运行 Dex 代码验证,并对所有的方法进行 AOT 编译。
  4. speed-profile:运行 DEX 代码验证,并对配置文件列出的方法进行 AOT 编译。

有许多 ART 构建选项可用于配置系统 ROM。如何配置这些选项取决于 /system 的可用存储空间以及预安装应用的数量。编译到系统 ROM 中的 JAR/APK 可以分为以下四个类别:

  • 启动类路径代码:默认使用 speed 编译过滤器进行编译。
  • 系统服务器代码:默认使用 speed 编译过滤器进行编译。
  • 产品专属的核心应用:默认使用 speed 编译过滤器进行编译。
  • 所有其他应用:默认使用 quicken 编译过滤器进行编译。

怎么验证手机上使用的编译模式?先 根据

adb shell

进入 adb shell ,再执行命令:

getprop | grep pm

getprop 是读取配置文件的意思,grep 是过滤选项,pm 是 package manager 的意思,最终如下:

PD1818:/ $ getprop | grep pm
[dalvik.vm.heapmaxfree]: [8m]
[dalvik.vm.heapminfree]: [4m]
[dev.pm.dyn_samplingrate]: [1]
[init.svc.dpmQmiMgr]: [running]
[init.svc.dpmd]: [running]
[persist.vendor.dpm.feature]: [11]
[persist.vendor.dpm.tcm]: [2]
[persist.vendor.radio.apm_sim_not_pwdn]: [1]
[pm.dexopt.ab-ota]: [speed-profile]
[pm.dexopt.bg-dexopt]: [speed-profile]
[pm.dexopt.boot]: [verify]
[pm.dexopt.first-boot]: [quicken]
[pm.dexopt.inactive]: [verify]
[pm.dexopt.install]: [quicken]
[pm.dexopt.shared]: [speed]

例如 pm.dexopt.first-boot 这个选项是 quicken,也是是这个手机对第一次启动的 app 采用 quick 模式编译,只验证 dex ,以及优化一些 dex 指令。pm.dexopt.bg-dexopt 模式下,则采用 speed-profile 模式,会根据配置文件进行 AOT 编译。

DexLayout

DexLayout 是 android 8.0 中引入的一个库,用于分析 dex 文件,并且根据配置文件进行重新排序。

默认的 apk 文件,等于 zip 包,zip 压缩工具默认按照文件名对文件进行排列。 Dexlayout 在app 运行期间会收集配置文件信息,然后在设备空闲的时候,把经常一起访问的文件集中在一起,对 dex 文件进行重新排序,可以改变文件位置,从而优化内存访问模式,进而节省 RAM 并且缩短启动时间。

综述

了解那么多一些底层的东西,那么实际涉及到的技术点是怎么样的?包括

  1. 热修复,类似 tinker 就是直接修改 dex
  2. 启动优化,除了优化业务代码, 包括 face book redex 或者 google 官方提供 pgo 操作,也是通过编译层面去优化启动速度的。

app 启动,是一个特别长久复杂的事情,需要了解各方面的知识才能把这个事情做得彻底。

参考资料:

Android Runtime (ART) 和 Dalvik

实现 ART 即时 (JIT) 编译器

配置 ART

Android dex(关于Dalvik、ART、DEX、ODEX、JIT、AOT、OAT)

Android 8.0 中的 ART 功能改进

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335