3.6 Android应用的运行时环境
Android独特的应用组件架构在某种程度上是Android多处理并发的产物。为了使该环境能够适应多个供应商的多种应用,信任每个供应商只需要很少的工作,Android执行Dalvik VM的多个实例,每个任务执行一个实例。在3.7节及后续的章节中,我们将探讨组件生命周期如何促进Android提高应用堆内的垃圾收集工作,以及如何促进多个堆之间的内存回收策略。
由于这种简单而又可靠的多处理方式,Android必须高效地把内存划分成多个堆。每个堆相对较小,这样内存可以支持多个应用同时运行。在每个堆中,由于有了组件生命周期而使得不使用的组件,尤其是当前不活跃的用户界面组件,在堆的空间紧张时能够执行垃圾回收,而在需要时能够重新获取。因此,由这种方式又引入了以数据库为中心的数据模型,其中大部分数据都是内在持久的,关于这一点本书后面将会更加详细地讨论,尤其是第11章。
3.6.1 Dalvik虚拟机
Android的多路处理利用了虚拟机的多进程和多实例,需要虚拟机的每个实例都能有效利用空间。这是通过组件生命周期来完成的,它使得对象某种程度上能够通过虚拟机本身执行垃圾回收和重新创建。Android通过Dalvik虚拟机运行特地为Android开发的字节码系统,该字节码系统名为dex。dex字节码的空间效率几乎是Java字节码的两倍,对于每个进程,从根本上看,在内存消耗上仅为Java类的一半。Android系统还使用写时复制(copy-on-write)的内存管理方式来实现同一个Dalvik可执行文件的多个实例之间的堆内存的共享。
3.6.2 Zygote:派生新的进程
当每个新的进程启动虚拟机的一个新的实例时,如果每次都加载所有必要的基类,则效率会很低。由于Android把每个应用放在独立的进程中,它会利用底层Linux操作系统的fork操作,通过模板进程生成新的进程,该进程在启动新的虚拟机实例时能够达到最优状态。该模板进程的名字就是Zygote。Zygote模板进程是Dalvik虚拟机的一个实例,它包含一组预加载类及Zygote进程的其他状态,这些进程通过fork操作生成Zygote的
副本。
3.6.3 沙盒:进程和用户
Android的安全在很大程度上依赖于Linux操作系统层的安全机制,尤其对于进程和用户级别的边界限制。由于Android面向的是个人设备,即个人持有和使用的设备,Android巧妙地利用了Linux内在的多用户支持特性:为每个应用供应商创建一个单独的用户。这意味着每个应用以不同的用户权限运行(除了那些来自同一个供应商的)。在默认情况下,一个应用所拥有的文件,其他应用是无法访问的。
这就类似于在Windows系统上,你以自己的用户名运行Word程序,而以同事的用户名运行Web浏览器。无论要切换查看Word还是Web浏览器,都需要首先退出,然后切换用户才能查看,而无法同时查看。Android允许一个登录的手机用户查看以不同的Linux级别用户运行的多个应用。
这种方式带来的直接影响是由于每个应用在自己的“独立运行空间(silo)”中执行,因而安全性得到了提高。
桌面操作系统通常不会如此全面地考虑应用的沙盒特征——一旦安装了某个应用,用户的所有数据都会信任该应用。Android设计师们设想的是来自众多供应商的很多小的应用,这些供应商并非都是完全可信的。因此,一个应用无法直接访问其他应用的数据。