常见Android编译优化问题梳理总结
作者:敲代码的老贾 发布时间:2021-08-17 11:21:48
编译常见问题
在开发过程中,有碰到过一些由于编译优化导致的代码修改并不符合我们预期的情况。这也就是之前为什么我经常说编译产物其实是不太可以被信任的。
方法签名变更,底层仓库的方法变更但是上层模块并没有跟随一起重新编译导致的这个问题。
常量优化,将一些常量的调用点直接替换成常量的值。
删除空导包, 没有用的一些导包就会做一次剔除。
踩坑1
我们最近碰到一个 pipeline
相关而且很妖怪的问题。我们一个 pipeline
会检查apk产物中是否存在异常的方法调用,就是之前介绍的在R8的基础上开发出来的A8。但是最近有一个类被删除了之后呢,但是代码中还有一处调用点。但是这个检测竟然被通过了,然后这部分代码就被合入了master。
这个引用的文件就如上图所示,是一个 debug buildType
中的,所以并不是所有的apk中都会存在这部分代码。
然后呢,这个 MergeRequest
就被合入了 master
分支,因为当天是我们出下一个版本包的时间,然后交付给测试的就是全量编译的 debug
和 release
包。别的开发同学rebase完master之后就发现 piepline
都跑不过了,就导致了他们当天的代码无法被合入。
这个就是事情大概的起因和经过,但是各位有没有想过为什么会发生这个问题吗。这个是不是我们的 pipeline
出现了bug,导致了这种问题无法被识别出来了呢。
以前有说过,如果简单的说我们的快编系统就是把模块替换成对应的aar,从而达到编译提速。所以因为我们使用的是这个模块对应的aar产物,所以大概率就是因为这个模块的编译产物和源代码有差异导致了这个问题。
其实这个问题一出现我就已经知道大概率是由空导包优化导致的这个问题,因为在 pipeline
检查的时候,检测的apk产物中确实不存在这个导包。因为我们使用的是一个历史版本的aar,其中无效导包的部分已经被编译器做了删除空导包的优化了。接下来我们看下我写的一个demo中的无效导包。
图一呢是源代码java文件,图二呢则是jar包中的代码。可以简单的看出来行号呢是可以对应的上的,但是这个 AppCompatActivity
的无效导包在产物中已经被优化掉了。这里也就回答了在编译过程中会保留行号,但是也会优化掉一部分不需要的代码,让我们编译出来的产物更小。
所以也就导致了我们的产物和我们的源代码之间的差异,另外一个角度就是说从apk中我们确实是不存在这个类的导包。但是呢在我们把这部分代码重新编译成aar的时候,就会出现source缺失,导致的语法树无法生成,之后导致的编译失败问题。
这也就是所以我一直和大家说编译产物是不可以被信任的呢。
踩坑2
这个是之前的一个故事了,我们之前呢在模块中定义了一些静态常量吧,然后用来标识当前SDK的版本,然后这个值在别的模块中被引用到了。
有一次因为需求变更,我们更改了这个静态变量的值,然后呢我就把这个需求提测了。之后测试反馈给我为什么这边的这个值没有变化啊。
我的天,当时我就是这样,发生了什么情况。然后呢我全量打了个包好了,我当时也就以为只是编译时的一个bug而已。然后后来呢,我查了下资料发现这个就是一个java编译时的常量优化问题。过了一阵子吧,我面试了下字节跳动,然后我和面试官也聊了下这个话题,然后呢在这个方法签名变更的问题上,当时我略输一筹,哈哈哈哈。接下来我们就看下一个demo。
图1呢也是java代码,图2呢则是aar中的编译产物。其中我们可以看到,这个静态常量在编译成产物之后就会被编译成这样。
所以这个就解释了我一开始碰到的这个问题,他就是由于我们的编译器已经把aar中的这部分静态常量编译成了直接的值,然后呢我们的源变化之后如果没有重新编译对应的模块,就会导致这个值一直无法被更新到最新的值。
来源:https://juejin.cn/post/7131995487736954893
猜你喜欢
- spring开启声明式事务导入依赖pom.xml<dependencies>  
- java字符串如何进行比较?我们可以根据内容和引用来比较Java中的String。它用于身份验证(通过 equals() 方法)、排序(通过
- 数据类型大小范围默认值byte(字节)8-128 - 1270shot(短整型)16-32768 - 327680int(整型)32-214
- 【题目】 汉诺塔问题比较经典,这里修改一下游戏规则:现在限制不能从最左侧的塔直接移动到最右侧,也不能从最右侧直接移动到最左侧,而是必须经过中
- 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知 n 个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。. 从编号为 k 的人开始
- 前置说明:这里的代码演示都是在UserController类里面使用UserService类,然后通过启动类调用UserController
- 1.Feign传统方式的不足①.在微服务架构中,当我们使用Feign传统方式进行服务调用的时候,需要在每个服务消费者中添加FeignClie
- 跨域的产生就是因为浏览器的同源策略。它是浏览器的核心安全功能,所谓的同源,就是指域名,协议,还有端口要相同。传统的方案就是JSONP(前端处
- 如何使用struts2 * ,或者自定义 * 。特别注意,在使用 * 的时候,在Action里面必须最后一定要引用struts2自带的 *
- 前言在实际开发当中,Spring中bean的属性直接赋值用的不是太多,整理这方面的资料,做一个小结,以备后续更深入的学习。通过配置文件的方式
- 本文实例讲述了Java中的多态用法。分享给大家供大家参考。具体分析如下:多态,是面向对象的程序设计语言最核心的特征。封装性、继承性都比较简单
- 在项目里,我需要做一个Spring Boot结合Thymeleaf前端模版,结合JPA实现分页的演示效果。做的时候发现有些问题,也查了现有网
- 最近一直在看RecyclerView,较之ListView它确实是灵活多变,给予开发者更多自定义的空间,比如:需要添加头部和尾部、item的
- 写在前面:使用springboot作为web框架,方便开发许多,做分布式开发,dubbo又不可少,那么怎么整合在一起呢,跟我学一遍,至少会用
- Spring Boot除了可以打可执行jar包外,也支持传统的war包。本文介绍如何使用Spring Boot构建传统war包。Spring
- 本文根据java开发人员在编码过程中容易忽视或经常出错的地方进行了整理,总结了十个比较常见的低级错误点,方便大家学习。1、不能用“==”比较
- 1 前言在前文中,已经讲述了 AOP 的后置处理器使用和方法,在本文中继续分享增强信息相关的源码,这里才是 AOP 的核心代码。2 spri
- 方法一:1.在pom.xml文件下添加依赖包<dependency><groupId>com.alibaba<
- 本文研究的主要是Hibernate hql查询的相关内容,具体如下。HQL介绍Hibernate语言查询(Hibernate Query L
- 在app中图片的轮播显示可以说是非常常见的实现效果了,其实现原理不过是利用ViewPager,然后利用handler每隔一定的时间将View