
深入理解Android Runtime
申国骏
2022-08-08 12:31·字数:2599·阅读:2340
imagepng
上图是Android整体的架构,Android Runtime之于Android而言相当于心脏之于人体,是Android程序加载和运行的环境。这篇文章主要针对Android Runtime部分进行展开,探讨Android Runtime的发展以及目前现状,并介绍应用Profile-Guided Optimization(PGO)技术对应用启动速度进行优化的可行性。转载请注明来源「申国骏」
App运行时演进
JVM
Android原生代码使用Java或者Kotlin编写,这些代码会通过javac或者kotlinc编译成class文件,在Android之前,这些class文件会被输入到JVM中执行。JVM可以简单分为三个子系统,分别是Class Loader、Runtime Data Area以及Execution Engine。其中Class Loader主要负责加载类、校验字节码、符号引用链接及对静态变量和静态方法分配内存并初始化。Runtime Data负责存储数据,分为方法区、堆区、栈区、程序计数器以及本地方法栈。Execution Engine负责二进制代码的执行以及垃圾回收。
imagepng
Execution Engine中,会采用Interpreter或者JIT执行。其中Interpreter表示在运行的过程中对二进制代码进行解释,每次执行相同的二进制代码都进行解释比较浪费资源,因此对于热区的二进制代码会进行JIT即时编译,对二进制代码编译成机器码,这样相同的二进制代码执行时,就不用再次进行解释。
imagepng
DVM(Android 21/22)
JVM是stack-based的运行环境,在移动设备中对性能和存储空间要求较高,因此Android使用了register-based的Dalvik VM。从JVM转换到DVM我们需要将class文件转换为dex文件,从class转换到dex的过程需要经过 desugar -> proguard -> dex compiler三个过程,这三个过程后来逐步变成 proguard -> D8(Desugar) 直到演变到今天只需要一步R8(D8(Desugar))。
imagepng
我们主要关注Android中Runtime Engine与JVM的区别。在Android早期的版本里面,只存在Interpreter解释器,到了Android22版本将JIT引入,这个版本Dalvik与JVM的Runtime Engine区别不大。
imagepng
ART-AOT(Android 44/50)
为了加快应用的启动速度和体验,到了Android44,Google提供了一个新的运行时环境ART(Android Runtime),到了Android50,ART替换Dalvik成为唯一的运行时环境。
imagepng
ART运行时环境中,采用了AOT(Ahead-of-time)编译方式,即在应用安装的时候就将dex提前编译成机器码,经过AOT编译之后dex文件会生成oat文件。这样在应用启动执行的时候,因为不需要进行解释编译,大大加快了启动速度。
imagepng
然而AOT带来了以下两个问题:
应用安装时间大幅增加,由于在安装的过程中同时需要编译成机器码,应用安装时间会比较长,特别在系统升级的时候,需要对所有应用进行重新编译,出现了经典的升级等待噩梦。
imagepng
应用占用过多的存储空间,由于所有应用都被编译成oat机器码,应用所占的存储空间大大增加,使得本来并不充裕的存储空间变得雪上加霜。
进一步思考对应用全量进行编译可能是没有必要的,因为用户可能只会用到一个应用的部分常用功能,并且全量编译之后更大的机器码加载会占用IO资源。
ART-PGO(Android 70)
从Android70开始,Google重新引入了JIT的编译方式,不再对应用进行全量编译,结合AOT、JIT、Interpreter三者的优势提出了PGO(Profile-guided optimization)的编译方式。
在应用执行的过程中,先使用Interpreter直接解释,当某些二进制代码被调用次数较多时,会生成一个Profile文件记录这些方法存储起来,当二进制代码被频繁调用时,则直接进行JIT即时编译并缓存起来。
当应用处于空闲(屏幕关闭且充电)的状态时,编译守护进程会根据Profile文件进行AOT编译。
当应用重新打开时,进行过JIT和AOT编译的代码可以直接执行。
这样就可以在应用安装速度以及应用打开速度之间取得平衡。
imagepng
imagepng
JIT 工作流程:
imagepng
ART-Cloud Profile(Android 90)
不过这里还是有一个问题,就是当用户第一次安装应用的时候并没有进行任何的AOT优化,通常会经过用户多次的使用才能使得启动速度得到优化。
imagepng
考虑到一个应用通常会有一些用户经常使用执行的代码(例如启动部分以及用户常用功能)并且大多数时候会有先行版本用于收集Profile数据,因此Google考虑将用户生成的Profile文件上传到Google Play中,并在应用安装时同时带上这个Profile文件,在安装的过程中,会根据这个Profile对应用进行部分的AOT编译。这样当用户安装完第一次打开的时候,就能达到较快的启动速度。
imagepng
imagepng
Profile in cloude 需要系统应用市场支持,在国内市场使用Google Play的占比非常低,因此cloud profile的优化在国内几乎是没有作用的,不过Profile的机制提供了一个可以做启动优化的思路。早在2019年,支付宝就在秒开技术的回应的里面提到过profile-based compile的技术,参考:如何看待今日头条自媒体发布谣言称「支付宝几乎秒开是因为采用华为方舟编译器」?,这也是我们一直研究Profile技术的原因。困扰着我们的一直有两个问题,第一个问题是如何生成Profile文件,第二个问题是怎么使用生成的Profile文件。对于第一个问题的解决相对还是有思路的,因为app运行就会生成profile文件,因此我们手动运行几次app就能在文件系统中收集到这个文件,不过如何以一种较为自动化的手段收集仍然是个问题。第二个问题我们知道Profile文件最终生成的位置,因此我们可以把生成的文件放到相应的系统目录,不过大多数手机和应用都没有权限直接放置这个文件。因此Profile优化技术一直都没有落地,直到Baseline Proflie让我们看到了希望。
Baseline Profile
Baseline Profile是一套生成和使用Profile文件的工具,在2022年一月份开始进入视野,随后在Google I/O 2022随着Jetpack新变化得到广泛关注。其背景是Google Map加快了发版速度,Cloud Profle还没完全收集好就上新版,导致Cloud Proflie失效。还有一个背景是Jetpack Compose 不是系统代码,因此没有完全编译成机器码,而且Jetpack Compose库比较大,因此在Profile生成之前使用了Jetpack Compose的应用启动会产生性能问题。最后Google为了解决这些问题,创造了收集Profile的BaselineProfileRule Macrobenchmark以及使用Profile的ProfileInstaller。
使用Baseline Profile的机制可以在Android7及以上的手机上得到应用的启动加速,因为从上述知道Android7就已经开始有PGO(Profile-guided optimization)的编译方式。生成的Profile文件会打包到apk里面,并且会结合Google Play的Cloud Profile来引导AOT编译。虽然在国内基本上用不了Cloud Profile,不过Baseline Profile是可以独立于Google Play单独使用的。
imagepng
在使用了Baseline Proflie之后,有道词典的启动速度从线上统计上看,冷启动时间有15%的提升。
这篇文章主要介绍了Android Runtime的演进以及对于应用启动的影响,下一篇文章我会详细介绍关于Profile&dex文件优化、Baseline Profile工具库原理,以及在实际 *** 作上如何使用的问题,敬请大家期待一下!
开发一个安卓软件大约需要多长时间,需要经历什么步骤
如今,不少企业都想拥有属于自己企业或产品的手机APP,但其中最困扰企业主的问题就是:开发一款手机APP到底需要多少钱?
简单点来说,要视手机APP的需求及质量而言,价位一般在几千到十几万左右,更高端的价格更高。
今天,我们就来详细分析一下这个问题,请继续往下看吧。
一、APP开发款式分为固定款和定制款,两者的价格均不相同
固定款:是指直接套用已有的、现成的APP固定模板,报价是固定的,所需要的功能也是固定的,缺点就是客户拿不到源代码,也不能根据企业需求进行定制,由于源代码是封装的,如果企业以后想进行功能升级或系统维护的话,也不能够实现,只能重新开发一个新的软件。
固定款的APP开发时间短,约2~3日的时间即可完成,费用大约在几千到几万之间。
定制款:定制款是指APP的功能全部重新开发,过程比较繁琐,需要美工、策划、APP开发(前台/客户端/手机端)、后台程序员等工种协同完成,大型的、功能复杂的APP甚至需要数十人的团队。
由于APP的功能和设计都是定制的,因此价格会高些。定制款的开发时间与开发价格是成正比的,开发时间长,大约在两三个月甚至不定的周期里才能完成,而费用大概在几万甚至十几万左右。
因此,想要知道开发一款手机APP需要花费多少钱,企业主首先必须把APP的详细需求和功能告知APP开发公司,开发公司才能报出一个合理的价格。
二、手机APP平台不同,制作成本也不一样
现在市面上流行的手机APP制作平台主要有两种一般包括两种系统:安卓系统(Android)和苹果系统(IOS)。
一般来说,制作苹果系统的手机APP软件费用要比安卓平台的贵一些,因为苹果公司对苹果平台的封闭性和手机APP开发语言Objective-C的难度,都让APP开发者加大了苹果系统手机APP开发的难度。
三、APP制作成本包含参与人员的工资
通常情况下,开发一款APP需要产品经理、客户端工程师、后端工程师和UI设计师各一名,这已经是制作手机APP应用软件比较精简的配置了,所以这些参与人员的工资也是包含在APP制作成本当中的。这些工作人员的月薪加起来可能都会超过4、5万元。
四、APP开发公司的所在地
需要注意的是,同样实力的APP开发公司,在不同的城市也会导致APP的成本费用高一些,如在北京、深圳和上海等地的开发公司开发成本费用就会比较高,因为当地开发人员的薪资和其他支出相对更高。
一般情况下使用eclipse,配置好eclipse的android开发环境,建立android工程。
编写程序(即java语言程序),完工后使用eclipse将工程直接打包成apk文件,然后安装在android手机上,即可运行。
Android系统架构采用分层思想,这样可以减少层与层之间的依赖性
Android系统由以下几个部分组成:
应用程序(APPLICATIONS)
应用程序框架(APPLICATIONS FRAMEWORK)
Android运行时(ANDROID RUNTIME)
核心库
DVM(Dalvik Virtual Machine)
函数库(LIBRARIES)
Linux内核(LINUX KERNEL)
Android系统运行过程:
1加载内核
2执行init进程,init进程完成设备初始化,然后读取initrc文件并且启动外部程序Zygote。
3Zygote进程初始化Dalvik虚拟机,启动system_server并且进入Zygote模式,通过Socket等候命令。
4当执行一个Android应用程序的时候,system_server进程通过Binder IPC方式发送命令给Zygote,Zygote收到命令之后通过fork自身创建一个Dalvik虚拟机的实例来执行应用程序的入口函数,这样一个程序就启动完成了(每一个应用程序独自占据一个dalvik虚拟机实例)。
执行流程:
zygote创建进程的方法:
fork(),创建一个Zygote进程(这种方式不会被调用,因为只有一个Zygote进程)
forkAndSpecialize(),创建一个非Zygote进程
forkSystemServer(),创建一个系统服务进程
特点:
zygote进程可以再fork出其他进程
非zygote进程则不能fork出其他进程
system_server进程在终止后他的子进程也必须终止
执行过程:
当进程fork成功之后,执行的工作就交给了Dalvik虚拟机
Dalvik虚拟机首先通过loadClassFromDex()函数完成类的加载工作,每个类被成功解析后都会拥有一个ClassObject类型的的数据结构存储在运行时环境(Android Runtime)中,虚拟机使用gDvmloadClasses全局哈希表来存储和查询所有装载进来的类
字节码验证器使用dvmVerifyCodeFlow()函数对装入的代码进行校验
接着虚拟机调用FindClass()函数查找并且装载main方法类
随后调用dvmInterpret()函数初始化解释器并且执行字节码流。
Dalvik虚拟机的JIT
JIT(Just-in-time Compilation,即时编译),又称动态编译,通过在运行时将字节码翻译为机器码的技术,使得程序的运行速度更快。
冷路径和热路径
在函数中代码很少顺序执行,多数代码有很多执行路径。如果有些路径很少被执行,就被称为“冷路径”,如果有些路径经常被执行就被称为“热路径”。
主流的JIT包括两种字节码编译方式
method方式:以函数或者方法为单位进行编译,编译整个方法的代码,在“冷路径”上浪费过多的编译时间。并且耗费更多内存。
trace方式:以trace为单位进行编译,trace方式可以快速获得热路径,使用更短的时间更少的内存来编译代码。
碰到的问题是控制台程序安装到手机上后,没一个图标可以用来启动,以下转载的是加入后,在手机的"安装"下可以找到对应的图标打开程序需要改的地方我加了背景色
我们使用Carbide的向导,可以方便的建立一个控制台应用程序,步骤如下:
1、菜单File->New->Symbian OS C++ Project
2、在d出的对话框选择Generic Symbian OS->Basic consle application(EXE)
3、完成向导就成功创建了一个控制台应用程序
此引用程序能正确的在模拟器中运行。但是,传入真机后,安装成功,在程序项里却找不到此程序。
解决方案:
1、新建一个文件夹data,添加资源文件TestConsoleApp_regrss,内容如下:
#include <appinforh>
UID2 KUidAppRegistrationResourceFile
UID3 0x0E0C8D49 // 改为与mmp文件相匹配的UID3
RESOURCE APP_REGISTRATION_INFO
{
app_file="TestConsoleApp"; // 改为工程包含入口函数的文件名
embeddability = KAppNotEmbeddable;
}
2、在mmp文件中添加一下几行:
SOURCEPATH /data
START RESOURCE TestConsoleApp_regrss
LANG SC
TARGETPATH /private/10003a3f/apps
END
3、在pkg文件中加入对资源文件编译后的文件的引用:
"$(EPOCROOT)Epoc32/data/z/private/10003a3f/apps/TestConsoleApp_regrsc"-"!:/private/10003a3f/import/apps/TestConsoleApp_regrsc"
4、添加自签名,编译完成。
注:1、以上控制台程序名为TestConsoleApp,请自行更改为对应的程序名;
2、以上程序仅针对S60 3rd有效。
Eclipse开发Android程序如何在手机上运行
android开发不论是在真机上调试还是最终发布到真机上都非常简单,过程如下:
1、安装usb驱动
手机要能与电脑相连,当然要安驱动了。效果就是你插入手机,电脑显示驱动已识别。驱动安装的官方教程:>
android基于Linux内核,很多系统也都基于Linux内核。但是android的特别之处除了开发上的特点以外,还有一个就是程序在运行时的行为和以往我接触到的程序运行机制有很大不同。在传统PC机或者其他一些手机上,用户对应用程序有绝对的掌控权,在应用程序的系统菜单上选择“退出”或者“关闭”之类的选项会直接杀死进程,而在android系统中不是这样的。在android中,应用程序的生命周期并不是由应用程序自身直接控制的,而是由系统,当系统需要释放内存来运行新进程或者保证某些后台进程和前端进程顺利执行的时候才会释放相应应用程序的资源,这个释放过程有一个重要性的层次。
android中进程的层次如下(重要性由高到低):
1、前端进程。顾名思义,前端进程就是目前显示在屏幕上和用户交互的进程,在系统中前端进程数量很少,而这种进程是对用户体验的影响最大,只有系统的内存稀少到不足以维持和用户的基本交互时才会销毁前端进程。因此这种进程重要性是最高的。
2、可见进程。可见进程也拥有一个可视化的界面,只是目前不是最上层界面(最上层界面在前端进程里面),可见进程一般调用了OnPause(),可见进程比前端进程重要性低,但是在交互方面影响还是很大,因为用户可能随时切换过去,所以系统不会轻易销毁它。
3、服务进程。一个服务进程就是一个Service,它调用了startService,就是UNIX中说的守护进程,对用户不可见,但是保证了一些重要的事件被监听或者维持着某些状态,比如网络数据传输、后台音乐播放,这类进程在内存不足且为了保证前端交互的顺利进行的时候被销毁。
4、后台进程。这里叫后台进程可能会和一般意义上的后台进程混淆,要说明的是,android里的后台进程是调用了OnStop()的,可以理解成用户暂时没有和这个进程交互的愿望,所以这里后台进程有点“待销毁”的意思。
5、空进程。这是一种系统缓存机制,其实就是个进程的外壳,当有新进程创建的时候,这个空进程可以加快进程创建速度,当系统内存不足的时候,首先销毁空进程。
android中进程重要性层次
1、首先将手机设置为调试模式,方法:设置——应用程序——开发——USB调试,打上√即可。
2、用数据线连接至电脑,在电脑上安装豌豆荚,此时豌豆荚会帮你安装驱动,安装好后豌豆荚就可以连接上手机了用adb命令测试是否有装置已连接。
3、如果无法测试装置是否连接,就是用adb server启动服务项开始在真机上调试,在eclipse中选择Run——Run Configurations,在左边选择好你要调试的工程,然后将右边切换至Target标签下。
6连接至真机调试,可选第一个或第二个,这里我直接选择第一个,点击Run,等待几秒钟出现以下界面。
以上就是关于android启动执行多个runtime全部的内容,包括:android启动执行多个runtime、开发一个安卓软件大约需要多长时间,需要经历什么步骤、安卓手机怎么运行 java 的程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)