Android ART模式简介

新书上市《深入解析Android 5.0系统》

 以下内容节选自本书


Android4.4最大的变化就是引入ART模式来代替Dalvik虚拟机。ART是AndroidRuntime的缩写,它提供了以AOT(Ahead-Of-Time)的方式运行Android应用程序的机制。所谓AOT是指在运行前就把中间代码静态编译成本地代码,这就节省了JIT运行时的转换时间。因此,和采用JIT的Dalvik相比,ART模式在总体性能有了很大的提升,应用程序不但运行效率更高,耗电量更低,而且占用的内存也更少
ART和dalvik相比,系统的性能得到了显著提升,同时占用的内存更少,因此能支持配置更低的设备。但是ART模式下编译出来的文件会比以前增大10%-20%,系统需要更多的存储空间,同时因为在安装时要执行编译,应用的安装时间也比以前更长了。


ART和dalvik相比,系统的性能得到了显著提升,同时占用的内存更少,因此能支持配置更低的设备。但是ART模式下编译出来的文件会比以前增大10%-20%,系统需要更多的存储空间,同时因为在安装时要执行编译,应用的安装时间也比以前更长了。

 

开启ART模式


在Android中ART模式缺省是关闭的,如果我们希望启动ART模式,需要在“设置”应用中手工打开它。进入“设置”后,选择“开发者选项”,再点击“选择运行环境”,会弹出如选择DALVIK或ART的对话框。选择ART后,系统将会重新启动,然后系统的运行环境就会从Dalvik切换到ART模式。
让我们打开“设置”应用的代码,看看这种切换到底做了些什么。下面是DevelopmentSettings.java中的一段代码:
   builder.setPositiveButton(android.R.string.ok, newOnClickListener() {
       @Override
       public void onClick(DialogInterface dialog, int which) {
            SystemProperties.set(SELECT_RUNTIME_PROPERTY,newRuntimeValue);
            pokeSystemProperties();
            PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
            pm.reboot(null);
        }
    });
上面这段代码只是设置重新设置了属性SELECT_RUNTIME_PROPERTY的值,然后就重启设备。这个属性的定义如下:
String SELECT_RUNTIME_PROPERTY = "persist.sys.dalvik.vm.lib"
注意属性是以persist开头的,所以它的值在重新开机后也可以保存。这个属性定义的是当前使用的运行环境库,如果是dalvik,它的值为libdvm.so,如果是art,它的值为libart.so。通过这个属性,系统就能判断出需要运行的模式。
ART系统的源码位于目录art下,包含了以下目录:
build目录:存放了一些mk文件。
compiler目录:动态库libart-compiler.so的源码目录,它包含了一个ART的编译器。
dalvikvm目录:可执行文件dalvikvm的源码目录。
dex2oat目录:可执行文件dex2oat的源码目录。用来将dex格式的文件编译成可执行文件。dex2oat文件会链接libart-compiler动态库。
jdwpspy目录:可执行文件jdwpspy的源码目录。这是一个调试工具,通过socket接收VM中输出的消息并打印输出。
oatdump目录:可执行文件oatdump的源码目录。这是一个工具,能dump出art文件的信息。
runtime目录:动态库libart.so的源码目录。
test目录:包含了大量测试代码的目录。
tools目录:包含了几个脚本文件。

 

两种模式的区别


从系统的实现角度看,ART和Dalvik的区别只表现在两个地方。一处是在安装应用执行优化时,Dalvik模式下执行的是dexopt程序,而ART模式下执行的是dex2oat程序。这个在“11.5.5节dexopt(优化)命令”中已经介绍过来。通过dex2oat程序编译后得到的是elf格式的可执行文件,而不是以前的dalvik字节码了。
另一处是在运行应用时,Dalvik模式下系统为应用进程链接的是libdvm.so,而ART模式下链接的是libart.so。这两个库文件能够相互替换,是因为它们都实现了相同的接口。下面我们看看Android是如何来装载不同运行库的。
前面我们已经介绍过了,Zygote进程启动时会调用AndroidRuntime的start()函数来启动虚拟机,start()函数中有下面两行代码:
void AndroidRuntime::start(const char* className, const char*options)
{
    ......
   JniInvocation jni_invocation;
   jni_invocation.Init(NULL);
    ......
}
我们看看jni_invocation的Init()函数的代码:
bool JniInvocation::Init(const char* library) {
#ifdef HAVE_ANDROID_OS
  char default_library[PROPERTY_VALUE_MAX]; //从property中得到运行库的名称
  property_get(kLibrarySystemProperty,default_library, kLibraryFallback);
#else
  const char* default_library =kLibraryFallback;
#endif
  if (library == NULL) {
    library =default_library;
  }
  handle_ = dlopen(library,RTLD_NOW); // 装载运行库
  if (handle_ == NULL) {
    ...... //错误处理
  }
  // 装载三个VM的入口函数。
  if(!FindSymbol(reinterpret_cast(&JNI_GetDefaultJavaVMInitArgs_),
                 "JNI_GetDefaultJavaVMInitArgs")) {
    returnfalse;
  }
  if(!FindSymbol(reinterpret_cast(&JNI_CreateJavaVM_),
                 "JNI_CreateJavaVM")) {
    returnfalse;
  }
  if(!FindSymbol(reinterpret_cast(&JNI_GetCreatedJavaVMs_),
                 "JNI_GetCreatedJavaVMs")) {
    returnfalse;
  }
  return true;
}
JniInvocation的Init()函数中通过属性persist.sys.dalvik.vm.lib取得了运行库的名称,然后调用dlopen()来装载运行库,同时从动态库中读取了三个函数的地址,它们是JNI_GetDefaultJavaVMInitArgs(),JNI_CreateJavaVM()和JNI_GetCreatedJavaVMs()。这三个函数相当于是虚拟机的三个入口函数,通过调用它们,就能创建出虚拟机系统。



你可能感兴趣的:(android,Art)