【朝花夕拾】Android性能篇之(五)Android虚拟机

简介: Android虚拟机的使用,使得android应用和Linux内核分离,这样做使得android系统更稳定可靠,比如程序中即使包含恶意代码,也不会直接影响系统文件;也提高了跨平台兼容性。在Android4.4以前的系统中,Android系统均采用Dalvik作为运行andorid程序的虚拟机,在android发展中具有举足轻重的地位,而Android 5.0及以后的系统使用ART虚拟机取代Dalvik,在性能上做了很大的优化。

前言

       原文:【朝花夕拾】Android性能篇之(五)Android虚拟机

       Android虚拟机的使用,使得android应用和Linux内核分离,这样做使得android系统更稳定可靠,比如程序中即使包含恶意代码,也不会直接影响系统文件;也提高了跨平台兼容性。在Android4.4以前的系统中,Android系统均采用Dalvik作为运行andorid程序的虚拟机,在android发展中具有举足轻重的地位,而Android 5.0及以后的系统使用ART虚拟机取代Dalvik,在性能上做了很大的优化。本文将对这两款虚拟机做一些介绍,主要内容如下:

          

        阅读本文,建议结合笔者之前的两篇文章,了解一下JVM和Apk打包:

        【朝花夕拾】Android性能篇之(一)序言及JVM篇

        【朝花夕拾】Android性能篇之(四)Apk打包

 

一、什么是Dalvik?

       Dalvik是Google公司自己设计用于Android平台的虚拟机,是Android移动设备平台的核心组成部分之一。虚拟机的概念在前面文章中讲到过是,就是一个设备上开辟的一个虚拟空间,一个虚拟出来的设备。Dalvik就是这样,在android设备上虚拟出来的一个用于运行Android程序的空间。由于Android程序的开发语言是java,所以Dalvik的本质仍然是JVM,是一个特殊设计的JVM,没有遵循Java虚拟机规范。另外,值得一提的是,Dalvik的命名来源于其祖先生活在冰岛的一个叫做Dalvik的小渔村。

 

二、Dalvik在Android架构中所处的位置

            

       想必读者们对如上截图已经相当熟悉了——android系统架构图。从上图可以看到,Dalvik虚拟机在Android Runtime中,在Linux Kernel之上。我们都知道,Android其实就是一个操作系统,其底层基于Linxu Kernel,这一层有许多的驱动程序,主要完成操作系统所具备的功能。Android Runtime,即android的运行环境,我们可以类比于java的jre,即java平台运行期环境。Java程序的开发、编译和运行需要java的核心包(jdk/lib/和jre/lib)支持,然后通过JVM来运行java程序,同样android程序的运行也是如此,Libraries就相当于java的jdk/lib,是开发/编译android程序所需要的库,Android Runtime里面的Core Libraries里就相当于java的jre/lib,是运行android程序所需要的核心库,自然而然,Dalvik虚拟机也就类比于java中的JVM,用于运行android程序。

 

三、Dalvik的作用

       简单来说就是:Dalvik虚拟机在Android操作系统上虚拟出一个设备,用来运行android 应用程序。Dalvik是apk运行的温床,其作为面向Linux、为嵌入式操作系统特别设计的虚拟机, 主要负责完成对象的生命周期管理、堆栈管理、线程管理、安全及异常管理、垃圾回收等。Dalvik充分利用Linux进程管理的特性,对其进项了面向对象的设计,使得可以同时运行多个程序,而传统的Java程序通常只能运行一个进程,这也是为什么Android不采用JVM的原因之一。在Android中,每一个app进程对应一个Dalvik,多个app进程在运行,就对应多个虚拟机的存在,这样设计的好处就是,当一个应用crash后,只会影响自己所在的dalvik,而不会影响到整个系统,不同的进程之间(即不同的Dalvik之间)通过进程间通信来实现交互。

 

四、Dalvik和JVM的区别与联系

        Android程序也是用Java语言开发的,所以Dalvik本质上讲也是java虚拟机,那么Dalvik和JVM又有哪些区别和联系呢?主要有如下几点:  

      (1)本质上Dalvik也是JVM,是特殊设计的JVM,没有遵循java虚拟机设计规范。

      (2)JVM是基于栈的虚拟机,而Dalvik是基于寄存器的虚拟机,对于基于栈和基于寄存器的虚拟机的区别和优缺点,推荐阅读:基于栈虚拟机和基于寄存器虚拟机的比较,讲的简洁且易懂,咱们这里不深入展开。

      (3)JVM运行的是Java字节码文件,即.class文件,而Dalvik运行的是.dex(即Dalvik Executable)文件。.dex是在.class文件的基础上,经过DEX工具压缩和优化后形成的。如下图所示: 

             

        当javac将java程序编译成class后,dex工具将所有的class文件整合到一个.dex文件中,这样做使得各个类能够共享数据,在一定程度上降低了冗余,同时也使文结构更加紧凑。.dex格式也是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。实验表明,dex文件时传统jar文件的50%左右。下图为java .jar包中.class文件和android .apk中.dex文件对比图:

             

      (4)补充两个Davik的特征:

        1)Dalvik经过优化,允许在有限的内存中同时运行多个虚拟机的实例,每一个应用对应一个虚拟机实例,对应了一个进程,对应一个独立的Linux进程。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。

        2)Dalvik第一次加载后,会生成Cache文件,以提供下次快速加载,所以第一次会很慢。

 

五、Davik的孵化器——Zygote进程

       在Android系统中有个一特殊的虚拟机进程Zygote,他是虚拟机实例的孵化器。它在系统启动的时候就会产生,完成虚拟机的初始化、库的加载、预制类库和初始化操作。如果系统需要一个新的虚拟机实例,他会迅速复制自身,以最快的速度提供给系统。对于一些只读的系统库,所有的虚拟机实例都和Zygote共享一块区域。

 

六、Dalvik的致命缺点:拖慢Android系统速度

       Dalvik有个致命的弱点,就是Dalvik虚拟机一直被用户指责为拖慢Android系统运行速度而不如IOS的根源。主要原因如下:

  1、开发者因素

       Android起步比IOS晚,平台不成熟,初期开发者水平有限,对性能方面关注比较少,主要关注点在提供各种丰富多彩的应用上。

  2、运营商因素

       Android是开源的,不同的手机厂商往往对android系统进行定制,而各厂商的技术参差不齐,修改后的特性或新增的功能,对原生系统的性能也造成一定的影响。同时,Android比较开放,有些开发者不顾用户体验,为一些目的在后台做了一些小动作,比如收集用户信息等,拖慢整体速度。

  3、Dalvik运行时机制因素

       在编译Android程序的时候,首先java代码被编译成class文件,然后被java打包工具dx打包成.dex文件,然后.dex文件和资源文件一起被压缩成apk文件。Apk文件其实也是zip格式,只是后缀被修改为apk,读者可以自己解压一个apk试试看。Android应用的安装过程:复制apk安装包到data/app目录(见截图6.3.2,截图6.3.3)下,解压并扫描安装包,把dex文件保存到dalvik-cache目录(见截图6.3.4)下,并在data/data(见截图6.3.5)目录下创建对应的应用数据目录。这样每次用户点击图标运行android程序时,dalvik虚拟机就会用JIT(Android2.2及以后版本)的方法把dex文件翻译为机器码,然后再执行机器码。虽然Dalvik虚拟机已经被做过很多优化(.dex文件基础上被优化为.odex文件,o表示optimization,“优化”的意思),但因为此种机制的存在,先翻译再执行,所以Android在电量消耗和程序运行流畅程度上一直不太理想。    

       

                                                 截图6.3.1  Android中 /data目录

       

                                                       截图6.3.2 /data/app目录

       

 

                                         截图6.3.3   /data/app目录下应用的信息

       

 

                                        截图6.3.4   /data/dalvik-cache目录下的内容

       

 

                       截图6.3.5   /data/data目录下应用数据目录,存储对应应用运行中产生的一些数据

 

七、ART虚拟机取代Dalvik虚拟机

       在第六点中,我们讲到了,由于Dalvik虚拟机机制的问题,拖慢了android应用的速度。由此,ART(即Android RunTime)虚拟机应运而生,在Android4.4中可以在设置中切换选择Dalvik或ART作为虚拟机,在Android L(5.0)中就直接删除了Dalvik,而全面使用ART。ART在机制上做了优化,可以在第一次安装应用时,字节码就会预编译(即AOT编译:Ahead-of-time)成机器码,使其成为真正的本地应用。在点击桌面的应用图标运行时,无需再翻译字节码,而是直接运行机器码,从而提升了启动速度。另外,ART在英语单词中是“艺术”的意思,可见,ART虚拟机的设计是匠心独运,同时也是被其设计中所高度赞誉的。

       下图展示了Dalvik和ART对.dex文件的处理的对比情况:

   

 

八、ART的优缺点

  1、优点

       ART的AOT方式相比于Dalvik的JIT方式(Just-In-Time,即时编译,,参见JIT_百度百科),主要由如下的有优势:

    (1)ART抛弃了Dalvik的JIT方式,而采用AOT预编译方式,在安装apk的过程中,将.odex文件(.dex优化后的文件)预编译为二进制机器码,存储在设备中,以后每次启动应用的时候,直接运行机器码,而无需再翻译.odex,这样极大地提高了应用的启动速度。

    (2)每次运行时所做的工作也少了,这样占用了更少的CPU资源,也消耗了更少的电池资源。

    (3)ART也在开发者工具和垃圾回收器上做了改善。

             

                             Dalvik和ART在性能上的对比

  2、缺点

       硬币有正反面,ART的预编译,也带来了一定的劣势

    (1)增加了安装时间。在安装的时候需要预编译,无疑增大了安装的工作量,从而增大了安装时间,对于一些大的应用,可能需要几分钟的时间才能安装完。

    (2)需要更多的空间存储预编译后的机器码,无疑占用了更多的存储空间。当然,现在硬件设备更新换代很快,性能也非常好,相比于ART带来的优点,该缺点几乎没什么影响。

 

九、Android N对ART的优化

       在上一节中我们提到是,ART的机制使得apk在安装的时候比较耗时,为了改变这种状态,在Android N(Android7.0)中对此做了优化。Android N实现了一个使用AOT、解释、JIT混合模式的运行环境,这里使用的JIT是改进后的JIT,ART也提供了一种新的、更快的解释器。这种方式在apk安装的过程中不再进行预编译,第一次运行该应用相关程序后,在手机处于idle状态和充电的时候再将运行过的程序编译为机器码并存储在设备中。JIT提供了一套追踪机制来决定哪一部分代码需要在手机idle和充电的时候来编译(即热区域hot method的确定),这个追踪技术被称为Profile Guided Compilation,其工作原理如下:

      (1)应用程序第一次启动的时候,只会通过解释器执行,同时JIT会介入并针对hot methods执行优化工作。代码在执行期间会被分析,分析结果被保存起来,同步输出一种被称为profile information的信息保存到文件中。该文件中记录了需要离线优化的hot methods,影响程序启动速度的Classes,它们主要用于进一步优化程序的启动速度。

      (2)当设备处于idle状态并且在充电,就会进入Profile Guided Compilation服务,使用第一步中的profile information,生成二进制机器码,用于替代原始应用程序的相应部分。

      (3)应用程序在后续启动时,就可以根据实际情况在AOT/JIT/Interpreter中选择最合适的执行方式了。

        通过以上的步骤可以得知,因为有了Profile Guided Compilation,同一app会因为不同的用户行为产生不同的编译结果。

       我们可以概括性地做一个总结:第一次运行到某些模块的程序的时候(此次JIT信息不会持久化),产生一个文件来记录这些被执行的程序信息,从而实现了将以往在安装过程中预编译生成机器码的过程,延迟到手机处于idle和充电的时候来完成,最终实现既能避免漫长的安装等待,又不影响程序启动速度,还节约了空间(因为有些功能程序一直不被使用,就不需要编译为机器码占用空间),cpu资源,电池资源等的目的。 

 

参考资料

        Android为什么比IOS慢?

        Android ART虚拟机执行引擎详情

        Android7.0开发者版本新特性

        浅谈Android的ART虚拟机

相关文章
|
4月前
|
移动开发 监控 前端开发
构建高效Android应用:从优化布局到提升性能
【7月更文挑战第60天】在移动开发领域,一个流畅且响应迅速的应用程序是用户留存的关键。针对Android平台,开发者面临的挑战包括多样化的设备兼容性和性能优化。本文将深入探讨如何通过改进布局设计、内存管理和多线程处理来构建高效的Android应用。我们将剖析布局优化的细节,并讨论最新的Android性能提升策略,以帮助开发者创建更快速、更流畅的用户体验。
74 10
|
6月前
|
监控 Java 调度
探秘Java虚拟机(JVM)性能调优:技术要点与实战策略
【6月更文挑战第30天】**探索JVM性能调优:**关注堆内存配置(Xms, Xmx, XX:NewRatio, XX:SurvivorRatio),选择适合的垃圾收集器(如Parallel, CMS, G1),利用jstat, jmap等工具诊断,解决Full GC问题,实战中结合MAT分析内存泄露。调优是平衡内存占用、延迟和吞吐量的艺术,借助VisualVM等工具提升系统在高负载下的稳定性与效率。
108 1
|
1月前
|
算法 JavaScript Android开发
|
6月前
|
传感器 安全 Android开发
探索iOS与安卓应用开发的性能差异
在移动操作系统领域,iOS和安卓的较量从未停歇。本文将深入探讨两大平台在应用开发中的性能表现,揭示它们各自的优势与局限。通过对比分析,我们将理解开发者如何在这两个不同的生态系统中做出权衡,以及这些选择如何影响最终用户的体验。
39 0
|
3月前
|
Android开发 开发者 索引
Android实战经验之如何使用DiffUtil提升RecyclerView的刷新性能
本文介绍如何使用 `DiffUtil` 实现 `RecyclerView` 数据集的高效更新,避免不必要的全局刷新,尤其适用于处理大量数据场景。通过定义 `DiffUtil.Callback`、计算差异并应用到适配器,可以显著提升性能。同时,文章还列举了常见错误及原因,帮助开发者避免陷阱。
282 9
|
3月前
|
安全 Android开发 数据安全/隐私保护
安卓与iOS的对决:移动操作系统的性能与创新
在当今智能手机市场,安卓和iOS两大操作系统一直处于竞争状态。本文将深入探讨它们在性能、安全性和用户体验方面的不同,并分析这些差异如何影响用户的选择。
67 3
|
3月前
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
87 0
|
4月前
|
数据库 Android开发 开发者
打造高效安卓应用:从代码优化到性能提升
【8月更文挑战第2天】在移动设备的海洋中,安卓应用的效能直接关系到用户体验的好坏。本文旨在深入探讨如何通过代码层面的优化技巧和策略来提升安卓应用的性能。我们将一起探索减少内存消耗、避免不必要的CPU使用以及提高应用响应速度的方法。文章将结合具体的代码示例,为开发者提供可行的优化建议,帮助他们构建更流畅、更高效的安卓应用。
70 2
|
5月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
【7月更文挑战第28天】在 Android 开发中, NDK 让 Java 与 C++ 混合编程成为可能, 从而提升应用性能。**为何选 NDK?** C++ 在执行效率与内存管理上优于 Java, 特别适合高性能需求场景。**环境搭建** 需 Android Studio 和 NDK, 工具如 CMake。**JNI** 构建 Java-C++ 交互, 通过声明 `native` 方法并在 C++ 中实现。**实战** 示例: 使用 C++ 计算斐波那契数列以提高效率。**总结** 混合编程增强性能, 但增加复杂性, 使用前需谨慎评估。
154 4