Android ART虚拟机
2014-01-17 17:17
127 查看
Android 4.4提供了一种与Dalvik截然不同的运行环境ART(Android runtime)支持,ART源于google收购的Flexycore的公司。ART模式与Dalvik模式最大的不同在于,启用ART模式后,系统在安装应用的时候会进行一次预编译,将字节码转换为机器语言存储在本地,这样在运行程序时就不会每次都进行一次编译了,执行效率也大大提升。
2、应用启动更快、运行更快、体验更流畅、触感反馈更及时。
3、更长的电池续航能力。
4、支持更低的硬件。
2、更长的应用安装时间。
2、Android2.2版本提供了JIT机制提升性能;
JIT(Just-In-Time),用来在运行时动态地将执行频率很高的dex字节码编译成本地机器码,然后再执行。通过JIT,就可以有效地提高Dalvik虚拟机的执行效率。但是,应用每次运行的时候,部分字节码都需要通过JIT转换为机器码,降低了应用程序运行效率。而ART则是使用AOT进行处理(Ahead-Of-Time),所谓AOT是指在运行以前就把中间代码静态编译成本地代码,这就减去了JIT运行时的转换时间,因此,即使Dalvik采用了JIT,Dalvik总体性能还是不能与直接执行本地机器码的ART虚拟机相比。
AOT的编译器分两种模式:
1. 在开发机上编译预装应用;
C/C++开发应用程序的时候,编译器直接就把它们翻译成目标机器码。
2. 在设备上编译新安装的应用;
在应用安装时将dex字节码翻译成本地机器码。
1. JNI_GetDefaultJavaVMInitArgs -- 获取虚拟机的默认初始化参数
2. JNI_CreateJavaVM -- 在进程中创建虚拟机实例
3. JNI_GetCreatedJavaVMs -- 获取进程中创建的虚拟机实例
JniInvocation提供统一了接口:
libnativehelper\JniInvocation.cpp
frameworks\base\core\jni\AndroidRuntime.cpp
Dalvik : dex2opt
ART : dex2oat
两个运行环境产生的优化代码路径及文件名都为:/data/dalvik-cache/app/data@app@{package name}.apk@classes.dex,但是ART环境产生的优化代码文件大小明显比Dalvik环境产生大。OAT文件其实就是基于ELF格式的一种私有文件格式。
ART相关源代码:
OAT文件加载流程
1、读取oatdata符号地址获取Oat数据 startAddress。
2、读取oatlastword符号地址获取OAT数据 endAddress。
3、通过startAddress和endAddress定位Oat数据。
4、解析Oat数据。构建方法定位所需数据结构。
然后就可以调用加载OAT文件的代码了。
虚拟机切换设置
Settings> Developer Options> Select RuntimeART优点
1、系统性能的显著提升。2、应用启动更快、运行更快、体验更流畅、触感反馈更及时。
3、更长的电池续航能力。
4、支持更低的硬件。
ART缺点
1、更大的存储空间占用,可能会增加10%-20%。2、更长的应用安装时间。
Dalvik虚拟机性能优化
1、DEX代码安装时或第一次动态加载时odex化处理。2、Android2.2版本提供了JIT机制提升性能;
JIT(Just-In-Time),用来在运行时动态地将执行频率很高的dex字节码编译成本地机器码,然后再执行。通过JIT,就可以有效地提高Dalvik虚拟机的执行效率。但是,应用每次运行的时候,部分字节码都需要通过JIT转换为机器码,降低了应用程序运行效率。而ART则是使用AOT进行处理(Ahead-Of-Time),所谓AOT是指在运行以前就把中间代码静态编译成本地代码,这就减去了JIT运行时的转换时间,因此,即使Dalvik采用了JIT,Dalvik总体性能还是不能与直接执行本地机器码的ART虚拟机相比。
AOT的编译器分两种模式:
1. 在开发机上编译预装应用;
C/C++开发应用程序的时候,编译器直接就把它们翻译成目标机器码。
2. 在设备上编译新安装的应用;
在应用安装时将dex字节码翻译成本地机器码。
Android虚拟机适配
Zygote进程在启动的过程中,会创建一个Dalvik虚拟机。Zygote进程通过自我复制的方式来创建应用程序进程,省去的不仅仅是应用程序进程创建Dalvik虚拟机的时间,Zygote通过AndroidRutime::start函数创建Dalvik虚拟机。在Android系统中,Davik虚拟机实现在libdvm.so中,ART虚拟机实现在libart.so中,通过persist.sys.dalvik.vm.lib系统属性来选择运行指定虚拟机。无论Dalvik还是ART,都实现了三个相同的接口函数:1. JNI_GetDefaultJavaVMInitArgs -- 获取虚拟机的默认初始化参数
2. JNI_CreateJavaVM -- 在进程中创建虚拟机实例
3. JNI_GetCreatedJavaVMs -- 获取进程中创建的虚拟机实例
JniInvocation提供统一了接口:
libnativehelper\JniInvocation.cpp
jint JniInvocation::JNI_GetDefaultJavaVMInitArgs(void* vmargs) { return JNI_GetDefaultJavaVMInitArgs_(vmargs); } jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { return JNI_CreateJavaVM_(p_vm, p_env, vm_args); } jint JniInvocation::JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) { return JNI_GetCreatedJavaVMs_(vms, size, vm_count); }该函数间接调用以下函数来实现:
extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) { return JniInvocation::GetJniInvocation().JNI_GetDefaultJavaVMInitArgs(vm_args); } extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args); } extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize size, jsize* vm_count) { return JniInvocation::GetJniInvocation().JNI_GetCreatedJavaVMs(vms, size, vm_count); }libnativehelper\JniInvocation.h
static JniInvocation* jni_invocation_; void* handle_;//保存so库的首地址 jint (*JNI_GetDefaultJavaVMInitArgs_)(void*); jint (*JNI_CreateJavaVM_)(JavaVM**, JNIEnv**, void*); jint (*JNI_GetCreatedJavaVMs_)(JavaVM**, jsize, jsize*);因此JniInvocation对外提供的接口函数是由JniInvocation中定义的函数指针来实现。JniInvocation中定义的函数指针是在哪里初始化的呢?我们知道Android虚拟机是在Zygote进程中通过调用AndroidRuntime::start()函数启动的:
frameworks\base\core\jni\AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const char* options) { ... /* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env) != 0) { return; } onVmCreated(env); ... }在启动虚拟机前通过调用JniInvocation::Init()函数来初始化JniInvocation中声明的函数指针
bool JniInvocation::Init(const char* library) { #ifdef HAVE_ANDROID_OS char default_library[PROPERTY_VALUE_MAX]; property_get("persist.sys.dalvik.vm.lib", default_library, "libdvm.so"); #else const char* default_library = "libdvm.so"; #endif if (library == NULL) { library = default_library; } handle_ = dlopen(library, RTLD_NOW); if (handle_ == NULL) { ALOGE("Failed to dlopen %s: %s", library, dlerror()); return false; } //查找JNI_GetDefaultJavaVMInitArgs函数指针 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_), "JNI_GetDefaultJavaVMInitArgs")) { return false; } //查找JNI_CreateJavaVM函数指针 if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_), "JNI_CreateJavaVM")) { return false; } //查找JNI_GetCreatedJavaVMs函数指针 if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_), "JNI_GetCreatedJavaVMs")) { return false; } return true; }该函数就是根据persist.sys.dalvik.vm.lib属性值来加载不同的虚拟机动态库,并从动态库中查找JNI_GetDefaultJavaVMInitArgs,JNI_CreateJavaVM,JNI_GetCreatedJavaVMs函数首地址
bool JniInvocation::FindSymbol(void** pointer, const char* symbol) { *pointer = dlsym(handle_, symbol); if (*pointer == NULL) { ALOGE("Failed to find symbol %s: %s\n", symbol, dlerror()); dlclose(handle_); handle_ = NULL; return false; } return true; }
Dalvik字节码生成过程
应用安装时采用的代码优化方式不同:Dalvik : dex2opt
ART : dex2oat
ART本地码生成过程
Dalvik dex代码经过dex => optimized dex => JIT cache这个过程,内存中需要同时容纳odex和JIT cache两份代码;换成ART以后,就变成dex => oat,内存里只放oat就可以。两个运行环境产生的优化代码路径及文件名都为:/data/dalvik-cache/app/data@app@{package name}.apk@classes.dex,但是ART环境产生的优化代码文件大小明显比Dalvik环境产生大。OAT文件其实就是基于ELF格式的一种私有文件格式。
dex2oat编译过程
开发者开发出的应用程序经过编译和打包之后,仍然是一个包含dex字节码的APK文件。既然应用程序包含的仍然是dex字节码,而ART虚拟机需要的是本地机器码,这就必然要有一个翻译的过程。Android系统在应用程序安装时,通过dex2oat工具将应用的dex字节码翻译成本地机器码。ART相关源代码:
OAT文件加载流程
1、读取oatdata符号地址获取Oat数据 startAddress。
2、读取oatlastword符号地址获取OAT数据 endAddress。
3、通过startAddress和endAddress定位Oat数据。
4、解析Oat数据。构建方法定位所需数据结构。
然后就可以调用加载OAT文件的代码了。
相关文章推荐
- Android ART运行时无缝替换Dalvik虚拟机的过程分析
- Android ART虚拟机执行引擎-Interpreter(八)
- Android ART虚拟机
- Android Dalvik虚拟机和ART虚拟机对比
- Android Art 虚拟机 GC 机制之 java 部落的崛起
- Dalvik VM和JVM的比较以及Android新的虚拟机ART
- Android ART虚拟机执行引擎-JIT(九)
- Android ART运行时无缝替换Dalvik虚拟机的过程分析
- Genymotion 运行Android虚拟机出现错误:Unable to staart the virtual device.To find out the cause of the problem
- Android 6.0中art虚拟机编译dex时已完全放弃使用LLVM
- Android ART虚拟机和Dalvik虚拟机区别
- 用于Android ART虚拟机JNI调用的NativeBridge介绍
- Android面试补习(一).JVM,DVM,ART虚拟机
- Android ART运行时无缝替换Dalvik虚拟机的过程分析
- 如何检测android虚拟机是Dalvik还是ART?
- Android的新虚拟机ART
- Android ART虚拟机和Dalvik虚拟机区别
- Android ART运行时无缝替换Dalvik虚拟机的过程分析
- Android ART虚拟机执行引擎-本地代码的执行(十)
- Android ART运行时无缝替换Dalvik虚拟机的过程分析