极客时间已完结课程限时免费阅读

练习Sample跑起来 | 热点问题答疑第4期

练习Sample跑起来 | 热点问题答疑第4期-极客时间

练习Sample跑起来 | 热点问题答疑第4期

讲述:冯永吉

时长01:29大小1.36M

你好,我是孙鹏飞。今天我们回到专栏第 7 期和第 8 期,来看看课后练习 Sample 的运行需要注意哪些问题。另外我结合同学们留言的疑问,也来谈谈文件顺序对 I/O 的影响,以及关于 Linux 学习我的一些方法和建议。
专栏第 7 期的 Sample 借助于 systrace 工具,通过字节码处理框架对函数插桩来获取方法执行的 trace。这个 Sample 实现相当完整,你在日常工作也可以使用它。
这个 Sample 使用起来虽然非常简单,但其内部的实现相对来说是比较复杂的。它的实现涉及 Gradle Transform、Task 实现、增量处理、ASM 字节码处理、mapping 文件使用,以及 systrace 工具的使用等。
对于 Gradle 来说,我们应该比较熟悉,它是 Android 平台下的构建工具。对于平时使用来说,我们大多时候只需要关注 Android Gradle Plugin 的一些参数配置就可以实现很多功能了,官方文档已经提供了很详细的参数设置说明。对于一些需要侵入打包流程的操作,就需要我们实现自己的 Task 或者 Transform 代码来完成,比如处理 Class 和 JAR 包、对资源做一些处理等。
Gradle 学习的困难更多来自于 Android Gradle Plugin 对 Gradle 做的一些封装扩展,而这部分 Google 并没有提供很完善的文档,并且每个版本都有一些接口上的变动。对于这部分内容的学习,我主要是去阅读别人实现的 Gradle 工具代码和Android Gradle Plugin 代码
关于这期的 Sample 实现,有几个可能产生疑问的地方我们来探讨一下。
这个 Sample 的 Gradle 插件是发布到本地 Maven 库的,所以如果没有执行发布直接编译需要先发布插件库到本地 Maven 中才能执行编译成功。
另一个可能遇到问题的是,如果你想把 Sample 使用到其他项目,需要自己将 SampleApp 中其 p 的 e.systrace.TraceTag”类移植到自己的项目中,否则会产生编译错误。
对于字节码处理,在 Sample 中主要使用了 ASM 框架来处理。市面上关于字节码处理的框架有很多,常见的有ASM 和 Javassist 框架,其他的框架你可以使用“Java bytecode manipulation”关键字在 Google 上搜索。使用字节码处理框架需要对字节码有比较深入的了解,要提醒你的是这里的字节码不是 Dalvik bytecode 而是 Java bytecode。对于字节码的学习,你可以参考官方文档和《Java 虚拟机规范》,里面对字节码的执行规则和指令说明都有很详细的描述。并且还可以配合 javap 命令查看反编译的字节码对应的源码,这样学习下来会有很好的效果。字节码处理是一个很细微的操作,稍有失误就会产生编译错误、执行错误或者 Crash 的情况,里面需要注意的地方也非常多,比如 Try Catch Block 对操作数栈的影响、插入的代码对本地变量表和操作数栈的影响等。
实现 AOP 的另一种方是可以接操作 Dex 文件进行 Dalvik bytecode 字节码注入,关于这种实现方式可以使用dexer库来完成,在 Facebook 的Redex中也提供了针对 dex 的 AOP 功能。
下面我们来看专栏第 8 期。我从文章留言里看到,有同学关于数据重排序对 I/O 性能的影响有些疑问,不太清楚优化的原理。其实这个优化原理理解起来是很容易的,在进行文件读取的操作过程中,系统会读取比预期更多的文件内容并缓存在 Page Cache 中,这样下一次读请求到来时,部分页面直接从 Page Cache 读取,而不用再从磁盘中获取数据,这样就加速了读取的操作。在《支付宝 App 构建优化解析》里“原理”一节中已经有比较详细的描述,我就不多赘述了。如果你对“预读”感兴趣的话,我给你提供一些资料,可以深入了解一下。
预读(readhead)机制的系统源码在readhead.c文件中。需要说明的是,预读机制可能在不同系统版本中有所变化,所以下面我提供的资料大多是基于 Linux 2.6.x 的内核,在这以后的系统版本可能对 readhead 机制有修改,你需要留意一下。
从专栏前几篇的正文看,很多优化的内容是从 Linux 的机制入手的,如果你对 Linux 的机制和优化不了解的话,是不太容易想到这些方案的。举个例子,专栏文章提到的小文件系统是运行在用户态的代码,底层依然依赖现存文件系统提供的功能,因此需要深入了解 Linux VFS、ext4 的实现,以及它们的优缺点和原理,这样我们才能发现为什么大量的小文件依赖现存的文件系统管理是存在性能缺陷的,以及下一步如何填补这些性能缺陷。
作为 Android 开发工程师,我们该何学习 Linux 呢?我其实不建议上来就直接阅读系统源码分析相关的书,我建议是从理解操作系统概念开始,推荐两本操作系统相关的书:《深入理解计算机系统》和《计算机系统 系统架构与操作系统的高度集成》。Linux 的系统实现其实和传统的操作系统概念在细节上会有不小的差别,再推荐一本解析 Linux 操作系统的书《操作系统之编程观察》,这本书结合源码对 Linux 的各方面机制都进行和很详细的分析。
对于从事 Android 开发的同学来说,确实很有必要深入了解 Linux 系统相关的知识,因为 Android 里很多特性都是依赖底层基础系统的,就比如我刚刚提到的“预读”机制,不光可以用在 Android 的资源加载上,也可以拓展到 Flutter 的资源加载上。假如我们以后面对一个不是 Linux 内核的系统,比如 Fuchsia OS,也可以根据已经掌握的系统知识套用到现有的操作系统上,因为像内存管理、文件系统、信号机制、进程调度、系统调用、中断机制、驱动等内容都是共通的,在迁移到新的系统上的时候可以有一个全局的学习视角,帮助我们快速上手。对于操作系统内容,我的学习路线是先熟悉系统机制,然后熟悉系统提供的各个方向的接口,比如 I/O 操作、进程创建、信号中断处理、线程使用、epoll、通信机制等,按照《UNIX 环境高级编程》这本书的内容一步步的走就可以完成这一步骤,熟悉之后可以按照自己的节奏,再去学习自己比较感兴趣的模块。此时可以找一本源码分析的书再去阅读,比如想了解 fork 机制的实现、I/O 操作的 read 和 write 在内核态的调度执行,像这些问题就需要有目的性的进行挖掘。
上面这个学习路线是我在学习过程中不断踩坑总结出来的一些经验,对于操作系统我也只是个初学者,也欢迎你留言说说自己学习的经验和问题,一起切磋进步。
最后送出 3 本“极客周历”给用户故事“专栏学得苦?可能是方法没找对”留言点赞数前三的同学,分别是@坚持远方、@蜗牛、@JIA,感谢同学们的参与。
分享给需要的人,Ta购买本课程,你将得18
生成海报并分享

赞 1

提建议

上一篇
练习Sample跑起来 | 热点问题答疑第3期
下一篇
练习Sample跑起来 | ASM插桩强化练习
unpreview
 写留言

精选留言(3)

  • X
    2019-03-14
    文中有个笔误:“SampleApp 中其 p 的 e.systrace.TraceTag" 这句话我推测应该是"com.sample.systrace.TraceTag",同学们移植时要确保TraceTag的路径为com.sample.systrace.TraceTag,否则会报NoClassDefFoundError的。

    作者回复: 感谢告知

    共 3 条评论
    2
  • SunnyBird
    2019-01-27
    很棒 谢谢老师
    1
  • yuanyuan
    2020-02-08
    生成的trace html显示 activityStart(Did Not Finish) com.sample.systrace.MainActivity.onCreate.(Landroid.os.Bundle;)V(Did Not Finish), 实际上onCreate早运行完成了,感觉Trace一直卡在onCreate(),我自己手动插桩就是正常的,请问这是什么原因?
    展开