如何检测android虚拟机是Dalvik还是ART?
通过反射调用SystemProperty的get方法来查看persist.sys.dalvik.vm.lib属性值,Android系统提供了一个系统属性persist.sys.dalvik.vm.lib,它的值要么等于libdvm.so,要么等于libart.so。当等于libdvm.so时,就表示当前用的是Dalvik虚拟机,而当等于libart.so时,就表示当前用的是ART虚拟机。
android的apk dex,odex,oat,vdex,art文件区别 JVM Dalvik ART区别
JVM Dalvik ART区别
编译模式 JIT,AOT
上述提到的两种编译模式jit 和aot,可以理解为是一种编译策略
JIT (just in time) 运行时编译
AOT (Ahead-Of-Time) 运行前编译 Art的主要特征就是AOT
虽然说Android是基于Java的,Java使用JVM,但是Google为了更好的适应手机的特性(其实就是当时手机的硬件资源很有限,直接使用JVM,效果差),在JVM的基础上优化出了Dalvik/ART虚拟机,JVM加载的是.class文件,Dalvik虚拟机加载的是.dex文件, JAVA虚拟机基于栈结构,程序在运行时虚拟机需要频繁的从栈上读写数据,这个过程需要很多其它的指令分派与内存訪问次数,会耗费非常多CPU时间。Dalvik虚拟机基于寄存器架构。数据的訪问通过寄存器间直接传递,这种訪问方式比基于栈方式要快非常多
JIT(Just In Time。即时编译技术)和AOT(Ahead Of Time,预编译技术)两种编译技术:
JIT以JVM为例,javac把程序源代码编译成class字节码,JVM通过逐条解释字节码将其翻译成相应的机器指令,逐条读入,逐条解释翻译,运行速度必定比C/C++编译后的可运行二进制字节码程序慢,为了提高运行速度,就引入了JIT技术。JIT会在运行时分析应用程序的代码,识别哪些方法能够归类为热方法,这些方法会被JIT编译器编译成相应的汇编代码,然后存储到代码缓存中。以后调用这些方法时就不用解释运行了,能够直接使用代码缓存中已编译好的汇编代码,这能显著提升应用程序的运行效率(安卓Dalvik虚拟机在2.2中添加了JIT)
相对的AOT就是指C/C++这类语言,编译器在编译时直接将程序源代码编译成目标机器码,运行时直接运行机器码。
Dalvik虚拟机运行的是dex字节码,而ART虚拟机运行的是本地机器码
Dalvik运行的是dex字节码,依靠JIT编译器去解释运行;运行时动态地将运行频率非常高的dex字节码翻译成本地机器码,然后再运行,可是将dex字节码翻译成本地机器码是发生在应用程序的运行过程中,而且应用程序每一次运行的时候,都要做一次这个翻译工作,因此即使使用了JIT,Dalvik虚拟机的整体性能还是不能与直接运行本地机器码的ART虚拟机相比
在ART下,Android 应用在安装后,会进行一次预编译,将应用安装包中的dex字节码转换成机器码存储在本地(系统只能运行二进制程序),这样,应用在运行时,可以直接执行这些二进制程序,移除了运行时的解释运行,效率更高,启动更快,不过这样做导致了安装后应用所占的空间更大,安装时间更长
ART的运行原理:
在Android系统启动过程中创建的Zygote进程利用ART运行时导出的Java虚拟机接口创建ART虚拟机。
APK在安装的时候,打包在里面的classes.dex文件会被工具dex2oat翻译成本地机器指令,最终得到一个ELF格式的oat文件。
比如在/data/app/com.xxx.xxx/oat/arm/base.odex就是,虽然后缀还是odex但它的内容确实ELF格式可执行的机器码。像很多 预制的apk。比如/system/app/webview/oat/arm/webview.odex之类的也是如此
APK运行时,上述生成的oat文件会被加载到内存中,并且ART虚拟机可以通过里面的
1.oatdata和oatexec段找到任意一个类的方法对应的本地机器指令来执行。
2.oat文件中的oatdata包含用来生成本地机器指令的dex文件内容
3.oat文件中的oatexec包含有生成的本地机器指令。
ART优点:
系统性能的显著提升
应用启动更快、运行更快、体验更流畅、触感反馈更及时
更长的电池续航能力
ART缺点:
更大的存储空间占用,可能会增加10%-20%
更长的应用安装时间
.java------>.class------->.dex
.java文件经过javac编译器生成.class字节码 再经过。dx工具生成.dex
odex(optimized dex)即优化的dex
对于在dalvik环境中 使用dexopt来对dex字节码进行优化 生成odex文件 最终存在手机的data/dalvik-cache目录下
对于art环境,使用dex2oat工具来对dex字节码生成oat文件
oat文件是art的核心,oat文件包含oatdata和oatexec
前者包含dex文件内容,后者包含生成的本地机器指令,进而可以直接运行,同样保存在手机的data/dalvik-cache目录下
PMS(PackgetManagerService)--->installd(守护进程)------>dex2oat(/system/bin/dex2oat)
注意存放在data/dalvik-cache目录下的后缀名都仍为.dex 前者其实表示一个优化过的.dex文件 后者为.oat文件
可以在linux环境下file命令看文件类型,如果是这样的:Settings.odex: ELF 32-bit LSB shared object, ARM就表示它其实是可执行的二进制编码和oat是一样的,只不过是后缀没有改过来。因为普通的classes.dex用file命令去看是这样的:classes.dex: Dalvik dex file version 035 并不是可以直接直接执行的二进制文件。
DEX文件
对于android应用程序,本质上使用的是java开发,使用标准的java编译器编译出Class文件,和普通的java开发不同的地方是把class文件再重新打包成dex类型的文件,这种重新打包会对Class文件内部的各种函数表、变量表等进行优化,最终产生了dex文件
ODEX文件
odex文件是dalvik虚拟机对解压出来的class.dex文件做一定程度的优化,文件大小会减少,存放在/data/dalvik-cache目录下,这样做可以加快软件的启动速度,预先提取,减少对RAM的占用
不过,这个优化过程会根据不同设备上Dalvik虚拟机的版本、Framework库的不同等因素而不同。在一台设备上被优化过的ODEX文件,拷贝到另一台设备上不一定能够运行。
ODEX 文件比 DEX 文件更难反编译,这也在一定程度上提高了安全性,因此在一些系统预装或系统级应用大多采用了 ODEX 优化。
一般 ODEX 不直接运行,在 Dalvik 运行 ODEX 时,需要通过Just-In-Time(JIT)编译器进行优化,提高运行效率。JIT 是一种在运行时同步将字节码转化成机器码的编译器,Dalvik 直接运行转化后的机器码
ODEX的内容有odex文件头-dex文件-依赖库-辅助数据,odex文件在原来的dex文件头添加了一些数据,在文件尾部添加了程序运行时需要的依赖库和辅助数据,使得程序运行速度加快。
OAT文件
OAT 文件是 ART 运行的文件,是一种二进制可运行文件,包含 DEX 文件和编译出的本地机器指令文件,其文件格式类似于网络数据报文,包含文件头和文件体,文件头的 oatdata、oatexec 和 oatlastword 字段分别描述 DEX 文件位置和本地机器指令的起止位置。因为 OAT 文件包含 DEX 文件,因此比 ODEX 文件占用空间更大
由于其在安装时打包在里面的classes.dex文件会被工具dex2oat翻译成本地机器指令,最终得到一个ELF格式的OAT文件,ART 加载 OAT 文件后不需要经过处理就可以直接运行,它没有了从字节码装换成机器码的过程,因此运行速度更快。
art文件
看到上面有art文件,.art是一些类/filed/方法,app启动直接map到内存,从odex中拆分出来的,art文件主要为了加快应用的对“热代码”的加载与缓存
2.4. vdex文件
google在android8.0新增加了vdex文件,其中包含 APK 的未压缩 DEX 代码,另外还有一些旨在加快验证速度的元数据。
VDEX 文件有助于提升软件更新的性能和用户体验。VDEX 文件会存储包含验证程序依赖项且经过预验证的 DEX 文件,以便 ART 在系统更新期间无需再次解压和验证 DEX 文件。无需执行任何操作,即可实现该功能。该功能默认处于启用状态。要停用该功能,请将 ART_ENABLE_VDEX 环境变量设为 false。
现在很多Android都需要预装很多apk,这些apk主要在/system/app,/system/priv-app/,/system/vendor/app等目录下。如果没有做odex优化,在首次开机时,systemService.java 会调用PackageManagerService.java对这几个目录下的apk多dexopt的优化,生成oat文件。apk越多,首次开机的时间也就越长。首次开机时,通常在手机上开到正在优化第*个应用,总共 * 个应用。就是在对apk做dexopt的优化。
如果我们要提高首次开机的速度,可以做如下设置:
1、在工程代码 /device/qcom/项目名/BoardConfig.mk 修改下面两个设置:
修改下面两个设置,在编译时,对jar,apk都做odex优化,生成对应的odex文件
DISABLE_DEXPREOPT := false
WITH_DEXPREOPT := true
如果不想在编译时做odex优化,可以注释掉这两行,或者把这两个值设置成:
2、如果设置了:
DISABLE_DEXPREOPT := false
WITH_DEXPREOPT := true
在编译的时候,/system/framework/目录下面的jar包,和/system/app,/system/priv-app/,/system/vendor/app下面的apk文件,都会在编译时,做odex优化。
如果不想jar包做odex优化,可以在/buid/core/java_library.mk文件中设置:
LOCAL_DEX_PREOPT := false
这样在编译时,jar包就不会做odex优化。
3、在实际开发过程中,有些apk如果做了odex优化,可能会出问题,可以通过在apk的编译目录Android.mk文件中添加:
LOCAL_DEX_PREOPT := false
这样该apk就不会做odex优化。
android底层之什么是Zram?
ZRAM(压缩内存)是linux的一种内存优化技术,基本工作原理是在内存中开辟一块区域,将压缩过后的硬盘数据放入该区域,以实现高速读取。假如原来150MB的可用内存现在可以放下180MB的东西,这样就可以让后台程序更少被系统砍掉罢了,但是这个压缩动作会少量加重CPU负担。这个在内存中专门开辟出来的区域作为swap使用,我们知道传统的swap是把flash划分一部分出来作为swap使用,但是从flash中读取速度比较慢,而在内存中读取数据却快很多。至于为什么存储的内容要压缩,如果不压缩的话那就没必要用这种技术了,直接在内存中划分一块区域作为swap就好了了,这样内存就变小了,变得毫无意义了。因为swap本意是为了解决物理内存不足,专门在存储内存中分一部分区域充当部分内存的角色,一般多用来存储切换到后台长时间没有操作的程序。利用zRAM并不是减小Android的内存占用,而是通过zRAM来提供交换空间,从而在内存紧张时释放出更多的可用内存,同时又避免传统的交换到文件系统的开销。ZRAM是分出一块物理内存,然后让系统当作虚拟内存来使用。传统的虚拟内存是存放在磁盘上的,而ZRAM存在内存里,并会进行压缩。这样的虚拟内存访问速度可以提高很多,内存利用率也会大幅提高。所以对于小内存设备,比如512M内存的Android设备,或者1G内存的电脑,都会有很大帮助。
android性能优化
android性能优化文档:https://www.jianshu.com/p/c09c31038c43