QQ音乐Android端120万行代码,编译耗时是怎样优化的,凭借这份《数据结构与算法》核心文档

在本文的后续内容中,将介绍几个重点模块的实现。

5. 核心原理

代码编译

(1)获取改动文件并进行编译

首先需要考虑的问题是,如何识别出用户改动了哪些文件?

我们的做法是,在每次编译成功后,收集所有工程文件的最后修改时间,保存为一份文件快照。在下次编译开始时,组件会生成最新的文件快照,与上一次的文件快照进行比对,就可以收集到用户改动过的文件了。

为了能够单独编译这些文件,还需要解决类引用的问题。

在首次完整编译工程时,组件会收集所有生成的class文件,放到缓存目录中。在编译被改动的文件时,会调用原生的javac或者是kotlinc程序,将刚才的缓存目录作为classpath传递进去,就可以解决编译时代码引用的问题了。

(2)进行代码依赖分析

上文中,提供classpath可以使编译阶段成功执行,却无法确保运行期的代码逻辑是正确的。举个例子,某个类修改了某个方法的参数列表,那么除了这个类需要被编译外,依赖这个类的其他类,也是需要重新编译的。否则,就会在运行期,出现NoSuchMethodException。

因此,由于代码之间相互依赖关系的存在,仅仅收集被用户改动的代码来编译,是不够的。还可能需要找出它的子依赖集,纳入编译范围。

沿着这个思路,还需要考虑两个问题:

  • 如何得到改动类的变化类型? 修改方法内部实现等类型的改动,是不会影响到其子依赖集的。在确保编译正确的前提下,为了尽可能地减少参与编译的代码数量,我们需要得到被改动类的变化类型,才能够决定是否需要将其子依赖集重新进行编译。
  • 如何得到改动类的子依赖集? 这个很好理解,只有计算出某个类的子依赖集,组件才能知道要编译什么。

想获取这两项信息,都需要对类的内部结构进行分析,提取出类名、类的修饰符、成员变量、方法等数据。我们的做法是,引入ASM工具对class文件进行解析,然后将解析出来的信息,保存到自定义的ResolvedClass数据结构中。

接下来的解决方案是这样的:

  1. 在全量编译期间,组件会同步启动一个独立的进程,对所有的class文件进行遍历分析,得到对应的ResolvedClass信息,并保存在本地文件中。其中,如果发现某个类引用了另一个类,那么就会把当前类的类名,添加到被引用类的子依赖集列表中(resolvedBy字段)。

  2. 触发增量编译后,组件首先编译改动类,得到新的class文件。然后启动代码依赖分析流程,解析出新的ResolvedClass,将其

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值