ART虚拟机介绍
ART全称是Android Runtime,指的是为Android应用提供运行环境的虚拟机,所以叫ART虚拟机。ART最初是Dalvik虚拟机,从Android 4.4开始逐渐抛弃Dalvik虚拟机进行针对性优化、引入新的特性,渐渐脱离Dalvik成为独一无二的ART虚拟机。
ART整体架构
ART整体分为Compiler&Interpreter和Runtime两个部分,它们的具体内容如下:
- Complier&Interpreter 负责对代码进行处理
- 解释器,用于解释执行字节码
- JIT Just-in-Time 即时编译,在运行过程中将执行频率较高的函数编译为机器指令,从而提升运行速度和性能
- AOT Ahead-of-Time 预先编译,在运行开始前对部分代码进行预先编译,从而提升运行速度和性能
- Runtime 提供对Java语言机制的支持
- 内存管理
- 线程
- 异常
- 类管理
- JNI,Java Native Interface
- 调试
- ...
ART对象分配
在面向对象编程中,程序会创建许多个对象。在Android中,这些对象就需要由ART来分配合理的内存资源,在对象销毁时进行内存资源的回收和清理。
创建对象需要有类的定义,类定义决定着一个对象的大小(内存布局,比如类成员的大小和分布)和行为(函数信息)。在Java中,所有类都继承自Object
类,在Object
类中,有一个klass_
成员负责该对象所属类的类对象,还有一个monitor_
成员负责存储Hash
Code和锁信息。
类管理
对于某个类的一个对象,它分配到的空间取决于继承链,继承链上的所有成员都会被分配空间。在Java中,当类第一次被使用时,将会进行该类的加载。
内存分配
Android应用的内存分配是由ART虚拟机来处理的,也就是说应用的内存申请并不是向操作系统提出,而是向虚拟机提出,虚拟机则负责对OS内存的占用和布局。如下所示,
1 |
|
ART虚拟机使用不同的分配器来分配内存,对于不同的内存申请使用合适的内存分配器。ART的内存分配器有以下几种:
- TLAB
- 相当于局部Cache,分配速度快,但是体积小
- ROSallocator
- 内存体积中等,从VM mem pool中分配内存
- LOSallocator
- 申请的内存体积较大,虚拟机将向Linux系统申请内存并分配
内存回收
当对象不再被使用时,自然需要销毁对象,回收分配给它的内存资源,这就是内存回收。常见的内存回收机制有两种:GC和RC。
- GC机制全称Garbage Collection(垃圾回收),这种机制的做法是定期(或者根据某些条件)查找系统中不用的对象并释放内存。
- RC机制全称Reference Counting(引用计数),这种机制与GC不同,它对每一个对象进行引用计数,当计数为0时说明不再有引用者使用该对象,于是销毁对象释放内存。
Android系统采用GC机制进行内存回收,而IOS的Swift采用RC机制进行内存回收。两种方式各有优劣,GC机制因为不能及时回收内存,所以应用的内存占用较大;而RC机制则无法直接回收两个相互引用(或者多个对象形成环引用)但是无用的对象的内存。
在ART的内存回收机制中,对象的引用被分为强引用、软引用和弱引用。强引用不会被回收,软引用会在内存不足时被回收,而弱引用在GC被触发时就会被回收。GC的触发策略不同固件厂商各不相同,通常来说包括内存不足、VM占用内存到达某个警戒值或者其他条件(比如锁屏若干时间后触发GC回收内存)。
要进行GC,就要确定对象是否可以被回收,于是这里引入GC roots的概念。GC roots是指一些特殊的栈、引用或者静态变量,在GC时从这些roots出发进行遍历,并把所有遍历到的对象打上标记(mark),遍历完成后所有未被mark的对象就是孤立对象,这些无用的对象将会被回收。在进行内存回收时,有两种做法:
- Tracing GC 直接将所有未被mark的对象的内存
- Coping GC 这里先介绍一下内存碎片:因为各个应用每次申请的内存总是大小不一,所以久而久之会产生了内存碎片化问题,也就是有许多小的空闲内存块,但是缺少较大的完整内存块,从而难以满足较大体积的内存需求。Coping GC将mark过的对象拷贝集中到一个区域,然后释放之前的整块内存空间,从而消除了一部分内存碎片
在ART的内存回收策略中,前台GC(对前台应用进行的GC)采用Tracing GC的方式进行,以避免影响应用使用;后台GC(对后台进程,例如Service,进行的GC)采用Coping GC的方式,以避免内存碎片产生。
ART执行方式
在ART虚拟机,代码有三种执行方式,分别是:
- 解释执行,解释执行字节码
- JIT,在解释执行同时对函数进行打分,分数高(取决于打分策略)的函数将被编译为机器指令,从而提高之后执行该函数的速度
- AOT,以dex为单位进行预先编译,并将编译后的机器指令持久化存储下来,每次执行到相应部分时直接执行机器指令而无需解释执行字节码
ART栈管理
对于解释执行的部分,栈托管到虚拟机完成;对于编译过的部分,栈管理与native代码一致,遵循对应指令集的压栈约定。
对于解释执行和编译执行的切换,ART采用trampoline-bridge机制来进行。