带你读《深入理解Android:Java虚拟机ART》之一:本书必读

简介: 本书将关注Android系统中至关重要的部分——Java虚拟机ART。随着Android设备的大规模普及,ART虚拟机已经成为当今使用最为广泛的JVM之一。所以,对ART虚拟机进行研究有着非同寻常的意义。本书的出现在一定程度上填补了这方面的空白。

移动开发

深入理解Android:Java虚拟机ART

邓凡平 著

image.png

第1章

本书必读

1.1 概述

笔者写书向来是最后才写第一章。此时,全书的主体内容已完全确定,笔者在学习ART虚拟机以及编撰本书的过程中所遇到的问题、总结的经验和教训等才可以完整地汇总并分享给各位读者。所以,本章是全书的点睛之笔,为必读章节。并且,我相信随着读者阅读的深入,还会时常回顾本章。
总体来说,本书并不简单。其实,从本书的目标—Java虚拟机也可以想得到,对Java应用程序来说,虚拟机就算是操作系统了。哪一本讲操作系统的书会简单呢?
具体到Android ART虚拟机来说,本书以Android 7.0为参考,绝大部分待分析的源代码位于art目录中。
□包含C++代码1071个文件。其中,.cc文件中包含236 744有效代码行(即不算注释及空行),.h文件中包含74 710有效代码行。
□包含汇编文件1704个文件,覆盖x86、arm、mips的32位和64位6个CPU平台,有效代码共19 955行。
也就是说,我们的ART虚拟机是一个有着30多万行代码的庞然大物。针对这样一个复杂的系统,要想从一个对它略知一二的初学者成长为一个能品头论足甚至指点江山的熟练者,这一路的学习历程必然不会轻松。
接下来,笔者将介绍阅读本书时必须准备的工具。磨刀不误砍柴工,建议读者先把这些工具准备好之后再开始后面的学习。

1.2 准备环境和工具

为了更好学习ART,读者要准备好如下的环境或工具。

1.2.1 准备源代码

首先,我们需要一份Android 7.0的源代码。笔者在百度云盘上提供了本书所需的资料下载。读者也可以到清华大学开源软件镜像站按照网页里的说明下载。其官网地址为https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/。笔者总结其下载步骤如下。

image.png

源代码的量很大,读者需要有一个浏览它的工具,Source Insight是不二之选。下面我们来看看如何配置它。

1.2.2 准备Source Insight

Source Insight是阅读源码的必备工具,它是一个Windows软件,在Linux平台上可通过wine进行安装。
提示:Source Insight推出3.5版本之后,很长一段时间都没有更新。最近推出了全新的4.0版本。但经过笔者测试,4.0版本的Source Insight在Linux上表现不稳定,建议读者在Linux上使用3.5版本的Source Insight。下面的讲解也以3.5版本的Source Insight为主。
首先,打开Source Insight,通过菜单项Project→New Project新建一个源码工程。工程可建立在Android 7.0源码根目录。笔者存放的位置是~/workspace/aosp/android-7.0,工程名为android-7.0。
接下来我们要先设置源码文件的后缀名。在ART中,C++的实现文件以.cc为文件后缀名。而汇编源码存储在以.S为后缀的文件里。Source Insight默认的配置不识别.cc和.S为后缀的源码文件,所以我们需要修改它。
单击菜单项Options→Document Options,弹出图1-1所示的文件类型对话框。
图1-1用于为C++源码添加.cc结尾的文件类型。接着还要为汇编源码做类似的处理,来看图1-2。

image.png

image.png

接下来我们为android-7.0工程添加具体的源码文件。单击菜单项Project→Add and Remove Project Files,弹出工程文件选择对话框,如图1-3所示。
请读者添加如下目录到android-7.0工程中。
□art目录(通过图中的Add Tree按钮可添加整个目录):ART虚拟机源码文件。
□libcore目录:包含JDK相关源码文件。
□libnativehelper目录:包含JNI相关源码,如jni.h等。
□frameworks/base/cmds/am、frameworks/base/core、frameworks/base/include三个目录:包含Zygote相关源码文件。

image.png

另外,上述目录中还有很多用于测试的源码文件,数量非常多。由于它们对本书的学习并无影响,建议读者移除其中test目录下的源码文件—通过图1-2中的Remove Tree可移除指定目录中的源码。比如art/test包含的1800多个源码文件都可以移除。
接着要进一步配置Source Insight。ART是一个复杂系统,所以谷歌用了一些工具来辅助编写正确的源码。这些工具要求在源码函数声明、变量定义等地方使用一些特殊的宏,而Source Insight不认识这些宏,所以很多函数、变量都无法解析和识别。为此,我们需要配置Source Insight,让它忽略这些宏。配置方法下面将详细介绍。
首先,找到Source Insight的C.tom文件,它位于~/.wine/drive_c/Program Files (x86)/Source Insight 3/下。打开该文件,在文件末尾添加如下的内容。
[C.tom文件]
;C.tom是C Token Macros的意思,用于重定义C/C++文件中的宏
;下面的条目都是ART源码中出现的宏,我们将它们定义为空,这样,Source Insight碰到这些宏
;时就会忽略它们
SHARED_TRYLOCK_FUNCTION(...)
ACQUIRE_SHARED()
EXCLUSIVE_TRYLOCK_FUNCTION(...)
SCOPED_CAPABILITY
SHARED_REQUIRES(...)
REQUIRES(...)
UNLOCK_FUNCTION(...)
ASSERT_SHARED_CAPABILITY(...)
ASSERT_CAPABILITY(...)
__noreturn
__mallocfunc
EXCLUSIVE_LOCKS_REQUIRED(...)
LOCKS_EXCLUDED(...)
SHARED_LOCKS_REQUIRED(...)
SHARED_LOCK_FUNCTION(...)
DEFAULT_MUTEX_ACQUIRED_AFTER
ACQUIRE(...)
ACQUIRE()
RELEASE()
RELEASE_SHARED()
ACQUIRED_AFTER(...)
GUARDED_BY(...)
PACKED(...)
__nonnull(...)
OVERRIDE
SHARED_LOCKABLE
ATTRIBUTE_UNUSED
NO_THREAD_SAFETY_ANALYSIS
ALWAYS_INLINE
配置好C.tom后,关闭并重新打开Source Insight,单击Project→Rebuild Project,弹出图1-4所示的对话框。

image.png

图1-4中,选择Re-Create the whole project from scratch即可。
提示:图1-4所示对话框的下方展示了源码文件个数,笔者设置的工程包含源码文件8688个。

1.2.3 准备模拟器和自制系统镜像

阅读源码是学习虚拟机的主要方法。但在某些关键地方,有时候很难确定代码逻辑的走向,这时就需要在源码中加一些日志来辅助我们观察虚拟机的行为。在此,笔者推荐使用模拟器和自制系统镜像来帮助我们达到这个目标。
提示:自制系统镜像是由上文下载的Android源码文件编译而来。我们可以随心所欲地通过修改源码文件来定制Android系统。当然,这个由我们自己编译而来的系统只能跑在模拟器中。即便如此,这对我们学习ART虚拟机来说也是莫大的帮助。

1.2.3.1 准备好模拟器

读者需首先安装Android Studio。然后随便打开一个Android应用工程。单击菜单栏右边的avd manager图标,启动AVD界面,如图1-5所示。

image.png

图1-5中,笔者创建了两个虚拟设备,一个是运行Android 7.0系统的innost-7.0设备,一个是运行Android 9.0系统的innost-9.0设备。
单击图1-6中左下角的“Create Virtual Device”,出现图1-6所示的设备硬件配置界面。

image.png

读者可自定义硬件配置或者从谷歌相关手机产品中选一个手机型号。比如Pixel XL。然后单击图1-6右下角的Next。出现图1-7所示的系统镜像选择界面。


image.png

建议读者选择Nougat x86系统镜像。也就是说,我们后面要分析的ART虚拟机将以x86 CPU为平台。
为什么选择x86平台?
工作用的台式机或笔记本主要是x86平台。所以,模拟器运行x86系统镜像的速度非常快。笔者之前尝试过使用arm平台,但模拟器运行的速度较慢。另外,根据上一节笔者统计的代码量可知,6个CPU平台总汇编代码的有效代码行数/总有效代码行数大概为6.02%,平均每个CPU平台的汇编代码行数才占总代码行数的1%左右。从这一点可以看出,汇编代码虽然重要,但它不会影响虚拟机学习。值得注意的是,Android SDK从8.0开始就不再提供ARM平台的模拟器镜像文件。
虚拟设备准备就绪后,读者可以启动它。这时,这个虚拟设备运行的是官方提供的镜像。

1.2.3.2 自制系统镜像

现在,我们有了Android源码、虚拟设备和官方下载的镜像文件。接下来需要编译Android源码以生成一个系统镜像文件,然后用这个系统镜像文件来启动虚拟设备。如此,就达到了让虚拟设备运行我们定制的系统镜像的目标。
编译系统的步骤如下。

image.png

执行lunch命令后,会显示如图1-8所示的内容,里边是各种不同的目标设备。请读者选择第8项(下面将介绍第8项的来历)。它表示要编译设备类型为"innost"的设备,该设备使用的CPU为x86,编译类型为userdebug。接着看下一步。

image.png

最后,让模拟器使用我们编译得到的系统镜像文件,方法如下。

image.png


image.png


由于本书的目标是研究ART虚拟机,所以,我们自己编译的系统镜像并不需要包含太多的应用程序,只要保证系统启动必需的几个核心应用程序即可。为此,笔者在源码根目录/device下新增了一个名为innost的设备类型。图1-9展示了该目录下的文件。
图1-9展示了innost设备类型下包含的文件。当把这些准备好后,我们执行如下命令时才能出现图1-8中的第7和第8项。

image.png

提示:读者可从笔者分享的链接中下载如图1-9所示的innost设备目录文件。本书所有资源的下载说明见1.4节的内容。
如果读者下载了笔者分享的Android 7.0源码的话,device目录下已经包含了innost设备目录的文件。

1.2.4 小结

读者阅读到这个地方时,请检查下面的工作是否完成。

image.png

□有一份完整的Android 7.0的源码。读者可以从笔者提供的资源链接中下载,或者从清华大学开源镜像站下载(下载步骤见1.2.1节)。
□配置好Source Insight,包括添加.cc和.S为后缀的文件类型、修改C.tom文件。然后,导入ART虚拟机学习所需的源码目录(art、libnativehelper、libcore、frameworks/base/cmds/am、frameworks/base/core、frameworks/base/include,可以把test相关的源码去除)。
□下载Nougat x86系统镜像,创建好对应的模拟器,并启动它。
□编译7.0的源码。如果读者是自行下载的源码,请从笔者提供的资料链接中下载自制系统镜像所需的设备配置文件(存放在源码根目录/device下)。
□通过emulator命令使用自己编译出来的系统镜像文件启动模拟器。

1.3 本书的内容

本书大体上可以分为五个部分,笔者用表1-1来描述各个部分对应章节的内容和说明。请读者务必认真阅读(后续如果需要,也请经常回顾)。
提示:表1-1最后一列是笔者给各章节难度的一个主观评分。评分的目的在于提醒读者阅读各章时可能会感受到的难度。除了第6章有着超高难度之外,其他章节只要肯花时间,相信对大部分读者总能学会。另外,笔者自己在研究ART源码的时候会碰到这样一种情况,有些代码前几次阅读感觉难度比较大,但只要多读几次,总会有茅塞顿开的时候。或许这就是所谓的量变到质变吧。

image.png
image.png

笔者再次和读者强调两点:
□ART虚拟机是复杂系统,模块之间有非常强的耦合关系。读者需采用剥洋葱式的学习方法,逐步、多角度来学习它。比如,Heap模块本书有三处地方介绍了它。每一次介绍都只关注Heap模块一部分的知识。初学者切莫盯着一个知识点一头扎入,否则很难走下去。
□如果读者不是特别了解ART的话,建议严格按照本书的顺序来阅读相关章节。

1.4 本书资源下载说明

读者可通过笔者的博客blog.csdn.net/innost首页置顶文章“深入理解Android系列书籍资源分享更新”以查看本书的资源下载地址。目前本书提供的下载资料如表1-2所示。

image.png

如果说ART虚拟机是一座坚固的城堡的话,本书相当于在这个城堡上为读者们打开了好几个关键突破口。希望读者在此基础上继续研究ART虚拟机中其他有意思、有价值的领域。

相关文章
|
20天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
1月前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【2月更文挑战第30天】 随着Kotlin成为开发Android应用的首选语言,开发者社区对于其性能表现持续关注。本文通过深入分析与基准测试,探讨Kotlin与Java在Android平台上的性能差异,揭示两种语言在编译效率、运行时性能和内存消耗方面的具体表现,并提供优化建议。我们的目标是为Android开发者提供科学依据,帮助他们在项目实践中做出明智的编程语言选择。
|
1月前
|
安全 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【2月更文挑战第24天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin在Android开发中的普及,了解其与Java在性能方面的差异变得尤为重要。本文通过深入分析和对比两种语言的运行效率、启动时间、内存消耗等关键指标,揭示了Kotlin在实际项目中可能带来的性能影响,并提供了针对性的优化建议。
29 0
|
1月前
|
安全 Java Android开发
构建高效安卓应用:探究Kotlin与Java的性能对比
【2月更文挑战第22天】 在移动开发的世界中,性能优化一直是开发者们追求的关键目标。随着Kotlin在安卓开发中的普及,许多团队面临是否采用Kotlin替代Java的决策。本文将深入探讨Kotlin和Java在安卓平台上的性能差异,通过实证分析和基准测试,揭示两种语言在编译效率、运行时性能以及内存占用方面的表现。我们还将讨论Kotlin的一些高级特性如何为性能优化提供新的可能性。
64 0
|
1月前
|
存储 Java 数据安全/隐私保护
【JVM】Java虚拟机栈(Java Virtual Machine Stacks)
【JVM】Java虚拟机栈(Java Virtual Machine Stacks)
35 0
|
27天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
在开发高性能的Android应用时,选择合适的编程语言至关重要。近年来,Kotlin因其简洁性和功能性受到开发者的青睐,但其性能是否与传统的Java相比有所不足?本文通过对比分析Kotlin与Java在Android平台上的运行效率,揭示二者在编译速度、运行时性能及资源消耗方面的具体差异,并探讨在实际项目中如何做出最佳选择。
17 4
|
1月前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【2月更文挑战第24天】 在移动开发领域,性能优化一直是开发者关注的重点。随着Kotlin的兴起,许多Android开发者开始从传统的Java转向Kotlin进行应用开发。本文将深入探讨Kotlin与Java在Android平台上的性能表现,通过对比分析两者在编译效率、运行时性能和内存消耗等方面的差异。我们将基于实际案例研究,为开发者提供选择合适开发语言的数据支持,并分享一些提升应用性能的最佳实践。
|
25天前
|
缓存 Java C#
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍(一)
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍
67 0
|
1月前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【2月更文挑战第22天】随着Kotlin在Android开发中的普及,开发者们对其性能表现持续关注。本文通过深入分析Kotlin与Java在Android平台上的执行效率,揭示了二者在编译优化、运行时性能以及内存占用方面的差异。通过实际案例测试,为开发者提供选择合适编程语言的参考依据。
|
1月前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能对比
【2月更文挑战第28天】 在Android开发领域,Kotlin作为一种现代编程语言,逐渐取代了传统的Java语言。本文通过深入分析Kotlin和Java在Android平台上的性能差异,揭示两者在编译效率、运行速度以及内存消耗等方面的比较结果。我们将探讨Kotlin协程如何优化异步编程,以及Kotlin Extensions对提升开发效率的贡献。同时,文中还将介绍一些性能优化的实践技巧,帮助开发者在Kotlin环境下构建更加高效的Android应用。