[TOC]
## Android虚拟机
### android2.2~android4.4(JIT与Dalvik)
JIT是运行时编译,这样可以对执行次数频繁的dex代码进行编译和优化,减少以后使用时的翻译时间,虽然可以加快Dalvik运行速度,但是还是有弊病,那就是将dex翻译为本地机器码也要占用时间。
*****
JIT是"Just In Time"的缩写,就是"即时编译技术",与Dalvik虚拟机相关
我们使用Java开发android,在编译打包APK文件时,会经过以下流程
* Java编译器将应用中所有Java文件编译为class文件
* dx工具将应用编译输出的类文件转换为Dalvik字节码,即dex文件
* 之后经过签名、对齐等操作变为APK文件。
Dalvik虚拟机可以看做是一个Java VM,他负责解释dex文件为机器码,如果我们不做处理的话,每次执行代码,都需要Dalvik将dex代码翻译为微处理器指令,然后交给系统处理,这样效率不高。
为了解决这个问题,Google在2.2版本添加了JIT编译器,当App运行时,每当遇到一个新类,JIT编译器就会对这个类进行编译,经过编译后的代码,会被优化成相当精简的原生型指令码(即native code),这样在下次执行到相同逻辑的时候,速度就会更快。
### android4.4~android5.0(Dalvik和art并存)
Google在4.4之后推出了ART,用来替换Dalvik。4.4之后两种运行时环境共存(JIT 和 ANR),可以相互切换,但是在5.0+,Dalvik虚拟机则被彻底的丢弃,全部采用ART.
### android5.0+(art)
ART的策略与Dalvik不同,在ART 环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。之后打开App的时候,不需要额外的翻译工作,直接使用本地机器码运行,因此运行速度提高。
当然ART与Dalvik相比,还是有缺点的。
* ART需要应用程序在安装时,就把程序代码转换成机器语言,所以这会消耗掉更多的存储空间,但消耗掉空间的增幅通常不会超过应用代码包大小的20%
* 由于有了一个转码的过程,所以应用安装时间难免会延长。
### android7.0+(ART 即时 (JIT) 编译器)
一个 app 在安装时会生成相应的 oat 文件。在运行时,会加载其 oat 及 dex 文件。执行一个方法,可能有三种模式:**解释执行**、**执行 oat 机器码**、**JIT**。
Android 7.0 之后,为了加载 app 的安装速度,安装时生成 oat 文件只会做 smali 指令优化等少量优化工作,并不会立刻生成 oat 机器码。这也意味着 app 在安装之初运行是解释执行为主的。
在解释执行过程中,ART 会记录每个方法的调用次数,记录在方法对应的 ArtMethod 中。这个次数即该方法的热度。方法的热度达到设定值之后,这个方法会被标记为**热代码**,并触发 JIT,在运行时编译生成机器码,以便下次调用时直接执行机器码。这些热代码还在被记录到 app 的 profile 中,以便之后重新 oat 时编译这些热代码。
方法的三种执行模式可以在运行时动态切换,实际上同一进程中三种模式往往是共存的,而且同一方法的运行模式也可能随时切换。
## 内联优化
### 什么是内联及内联的生成时机
内联所做的事情就是
* 缩短调用链
* 缩短代码
* 提高运行速度
### 常见的内联类型
比较常见的内联类型有常量内联,字符串内联以及方法内联等常量内联
#### 常量内联
修饰的静态常量值直接替换到代码块里面,比较常见的是作用于编译期,可以体现在.class文件中。
#### 方法内联
方法内联是将被调用方的代码拷贝到调用方的调用处,从而减少代码函数定义及函数跳转等,提高运行效率。
根据我们下文的对生成时机的区分,还可细分为编译期内联优化,dex2oat内联优化和JIT内联优化
##### 1\. 编译期内联优化(混淆优化工具R8)
当Android Gradle插件升级至3.4.0,会引入一个新的混淆优化工具R8,这个工具可以对代码进行压缩优化,其中就包括了选择性内联。
(脱糖)Desugaring的工作原理是 R8/D8在字节码编译成Dex文件时,通过三方库的引入支持了原本不支持的高版本JDK语法,并一同打进dex,使之可以正常工作
使用R8优化包体积
R8在D8的基础上又增加了Proguard的能力,通过开启Shrinking,可以对源码进行优化,以达到减小包体积的目的,具体包括但不限于:
* 代码删除:通过语法树静态分析技术,发现并剔除未使用的代码,例如没有被实例化的Class等
* 代码优化:对运行时代码进行优化,包括死代码删除、未使用的参数删除、选择性内联、类合并等。
* 代码混淆:优化标识符名字,减少代码数量,例如MyAwesomeClass可能被优化成单一字母a
##### 2\. dex2oat内联优化(dex不可见优化)
ART(Android Runtime)是Android在4.4版本中引入的新虚拟机环境,在5.0版本正式取代了Dalvik VM。ART环境下,App安装时其包含的Dex文件将被dex2oat预编译成目标平台的机器码oat,从而提高了App的运行效率。在这个预编译过程中,dex2oat对目标代码的优化过程与Dalvik VM下的dexopt有较大区别,尤其是在5.0版本以后ART环境下新增的方法内联优化,改变了原本的方法分布和调用流程。优化dex2oat时方法内联优化的条件
dex2oat时,方法被内联优化的条件是实现在ART的源码中的,每个android版本都有一些明显的差异区别。内联优化特性是从kOptimizing Compiler引入的,最早出现在android 6.x,但是android 6.x默认使用的是kQuick Compiler。而到了android 7.x,kOptimizing Compiler成了默认的Compiler类型。对于Optimizing Compiler,当以下条件均满足时被调用的方法将被inline(仅针对Android N版本):
* App不是Debug版本的;
* 被调用的方法所在的类与调用者所在的类位于同一个Dex;(注意,符合Class N命名规则的多个Dex要看成同一个Dex)
* 被调用的方法的字节码条数不超过dex2oat通过--inline-max-code-units指定的值,6.x默认为100,7.x默认为32;
* 被调用的方法不含try块;
* 被调用的方法不含非法字节码;
* 被调用方法还不能包含对接口方法的调用。
此外,Optimizing Compiler的方法内联可以跨多级方法调用进行,若有这样的调用链:method1->method2->method3->method4,则在四个方法都满足内联条件的情况下,最终内联的结果将是method1包含method2,method3,method4的代码,method2包含method3,method4的代码,以此类推。但这种跨调用链内联会受到调用dex2oat时通过--inline-depth-limit参数指定的值的限制,默认为5,即超过5层的调用就不会再被内联到当前方法了。
##### 3\. JIT内联优化(dex不可见优化)
ART也包含一个具备代码分析功能的即时 (JIT) 编译器,该编译器可以在 Android 应用运行时持续提高其性能。JIT 会利用运行时类型信息,可以更高效地进行内联,并可让堆栈替换 (OSR) 编译成为可能。有些小伙伴对方法内联有个印象是频繁被调用的方法会发生内联,这一块工作就是JIT在运行时完成的。
- Android
- 四大组件
- Activity
- Fragment
- Service
- 序列化
- Handler
- Hander介绍
- MessageQueue详细
- 启动流程
- 系统启动流程
- 应用启动流程
- Activity启动流程
- View
- view绘制
- view事件传递
- choreographer
- LayoutInflater
- UI渲染概念
- Binder
- Binder原理
- Binder最大数据
- Binder小结
- Android组件
- ListView原理
- RecyclerView原理
- SharePreferences
- AsyncTask
- Sqlite
- SQLCipher加密
- 迁移与修复
- Sqlite内核
- Sqlite优化v2
- sqlite索引
- sqlite之wal
- sqlite之锁机制
- 网络
- 基础
- TCP
- HTTP
- HTTP1.1
- HTTP2.0
- HTTPS
- HTTP3.0
- HTTP进化图
- HTTP小结
- 实践
- 网络优化
- Json
- ProtoBuffer
- 断点续传
- 性能
- 卡顿
- 卡顿监控
- ANR
- ANR监控
- 内存
- 内存问题与优化
- 图片内存优化
- 线下内存监控
- 线上内存监控
- 启动优化
- 死锁监控
- 崩溃监控
- 包体积优化
- UI渲染优化
- UI常规优化
- I/O监控
- 电量监控
- 第三方框架
- 网络框架
- Volley
- Okhttp
- 网络框架n问
- OkHttp原理N问
- 设计模式
- EventBus
- Rxjava
- 图片
- ImageWoker
- Gilde的优化
- APT
- 依赖注入
- APT
- ARouter
- ButterKnife
- MMKV
- Jetpack
- 协程
- MVI
- Startup
- DataBinder
- 黑科技
- hook
- 运行期Java-hook技术
- 编译期hook
- ASM
- Transform增量编译
- 运行期Native-hook技术
- 热修复
- 插件化
- AAB
- Shadow
- 虚拟机
- 其他
- UI自动化
- JavaParser
- Android Line
- 编译
- 疑难杂症
- Android11滑动异常
- 方案
- 工业化
- 模块化
- 隐私合规
- 动态化
- 项目管理
- 业务启动优化
- 业务架构设计
- 性能优化case
- 性能优化-排查思路
- 性能优化-现有方案
- 登录
- 搜索
- C++
- NDK入门
- 跨平台
- H5
- Flutter
- Flutter 性能优化
- 数据跨平台