1. 为什么需要热修复技术
当我们的Android应用程序发布到各大市场上之后,如果出现了重大bug,大部分情况下只能通过紧急发包升级来解决问题,但是这会带来以下几个问题:
- 应用升级需要一定的时间,时效性差,如iOS应用发布审核可能需要好几天;
- 需要用户下载更新安装包,如果不是强制升级,用户可能不会选择升级,而强制升级会导致用户体验急剧下降,从而引起更多用户的流失;
- 如果是紧急重大bug,并且是发生在客户端的,我们无法控制用户手上的应用程序,无法采取任何有效的应急措施,可能造成不可挽回的损失;
当我们的Android应用程序采取了热修复技术之后,当发生上述情况时,及时更新上传热修复补丁包,能在用户无感知的情况下修复bug,这听起来是不是很完美。目前市面上的Android热修复技术很多,各个大厂都有自己成熟的热修复技术方案,我在这里并不是想重新造个轮子,而是逐步探究热修复技术的实现原理,这样在谈到热修复时能够做到游刃有余。实际上,它并没有我们想想中的那么高深莫测。
2. Android热修复的基石-虚拟机
Java应用程序是由Java虚拟机启动加载的,Android应用程序则是由Android虚拟机启动加载的,要了解热修复的原理,我们必须要对Android虚拟机有所了解。
通常在Java平台上我们采用的Java虚拟机,能够加载识别符合java规范的class文件或二进制字节流。在Android平台上,虽然应用程序也是采用java来编写的,但是它采用了与Java平台不同的虚拟机实现方案,通常它并不直接加载class文件,而是加载由一系列class文件组合而成的dex文件。
Android发展至今,虚拟机从最早的Dalvik虚拟机到现在的Art虚拟机,经历过多次优化,我们先总体了解下每个虚拟机的特点以及差别。
3. Dalvik虚拟机
Dalvik是Google公司自己设计用于Android平台的虚拟机。Dalvik虚拟机是Google等厂商合作开发的Android移动设备平台的核心组成部分之一。它可以支持已转换为 .dex(即Dalvik Executable)格式的Java应用程序的运行,.dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。Dalvik 经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik 应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。
这是百度百科里对Dalvik虚拟机的介绍,点击这里百度百科Dalvik可以查看具体介绍。
那么Dalvik与标准的JVM相比有什么特点呢,从百度百科里可以看到以下相关资料:
- 首要差别是Dalvik基于寄存器,JVM基于栈;
- Dalvik负责进程隔离和线程管理,每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行;
- Dalvik运行的是其专有的文件格式dex,而JVM运行的是java字节码;
- dex文件格式可以减少整体文件大小,提高I/O操作的类查找速度;
- odex是为了在运行过程中进一步提高性能,对dex文件的进一步优化;
- 为简化翻译,常量池只使用32位索引;
基于寄存器与基于栈的虚拟机有什么不同,本人也只懂皮毛,不在这里讨论了。我们可以看到,Dalvik虚拟机运行的是dex文件。.dex文件是Google创造的一种文件格式,它是由多个Java的.class文件转换而成,一个.dex文件包含了多个Java的.class文件信息。为了节省空间,.dex文件共用了很多类名称、常量字符串等,由同样的java代码编译而成的.dex文件与.jar文件相比,.dex文件体积会小很多。
Android应用打包成apk文件的过程为:将java文件编译后得到.class文件,.class文件通过dex转换工具编译成.dex文件,最后将资源文件和.dex文件打包成.apk文件。
4. ART虚拟机
在Android5.0及后续版本中,Google采用了ART正式取代了以往的Dalvik虚拟机。ART与Dalvik的主要区别有:
4.1 ART采用AOT技术替代了JIT
我们先了解下JIT与AOT这两个名词术语:
- JIT:Just In Time,及时编译技术。JIT会在运行时分析应用程序的代码,识别哪些方法可以归类为热方法,这些方法会被JIT编译器编译成对应的汇编代码,然后存储到代码缓存中,以后调用这些代码时就不用解释执行了,可以直接使用代码缓存中已编译好的汇编代码,能显著提升应用程序的执行效率。
- AOT:Ahead Of Time,预编译技术。编译器在编译时直接将源程序编译成目标机器码,运行时直接运行机器码。
Dalvik采用的是JIT技术,而ART采用的是AOT技术。ART在应用程序安装的时候,就已经将所有的字节码编译成了机器码,运行的时候直接运行的是机器码。而Dalvik则是在应用程序运行的时候,实时将字节码编译成机器码。因此,ART与Dalivk相比,省去了运行时将字节码编译成机器码的过程,极大地提升了应用程序的运行效率。
虽然运行效率有了提升,但同时带来了其他缺点:
- 安装时需要将字节码编译成机器码,因此ART需要更大的存储空间;
- 安装需要花更多的时间;
可以说,这是一个以空间换时间的策略,但是在存储设备越来越便宜的今天,以空间换时间应该是一个比较划算的方式。
4.2 提搞了垃圾回收效率
Dalvik在gc时,会挂起虚拟机内部的所有线程,然后gc查找所有可回收的对象进行回收,回收完成后恢复所有挂起的线程。需要注意的是,gc与应用程序的运行并不是并发执行的,发生gc时就会出现平常我们所说的Stop The World现象,应用程序如同停止了一样,如果gc频繁或者gc时间过长都会导致应用程序运行卡顿。
ART对gc做了一定的改善,Dalivk的gc操作与应用程序是同时执行的(非并发),而ART则将原来的非并发过程改成了部分并发,缩短了gc时间,提升了垃圾回收的效率。
4.3 提高了内存使用率、减少了内存碎片化
Dalvik虚拟机垃圾回收采用了Mark and Sweep算法,即“标记-清除”算法,这种算法先对需要回收的内存区域进行标记,然后再统一清除,它是一种比较
高效的算法,但是带来的弊端是会造成可用内存块的不连续,碎片化严重。虚拟机多次gc之后,本来连续的内存区域变得千疮百孔,以后为对象分配内存寻址会越来越难。
而ART在内存分配上做了优化,比如它开辟了一块名为Large Object Space的内存区域,专门用来存放大对象,同时还引入了一个名为moving collector的技术,专门用来将gc后不连续的物理内存块对其,解决了Dalvik上内存碎片化严重的问题。
5. 小结
本文只是对Dalvik与ART做了一个初步的介绍,先明白一个大概原理,这样才能逐步理解热修复的过程。