-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4382212
commit f80598f
Showing
2 changed files
with
104 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# Android 性能优化技术月报 | 2024 年 10 月 | ||
每个月都会有一些 Android 性能优化相关的优质内容发布,然而,碎片化阅读使得这些知识难以形成完整体系,且容易被遗忘。为解决这些问题,我决定尝试使用技术月报的形式,总结我在最近一个月内查阅的 Android 性能优化相关的优质内容。 | ||
|
||
月报的主要内容包括:整理展示我在最近一个月所查阅的 Android 性能优化领域的最新技术动态、精选博客,精选视频等内容。 | ||
|
||
## 精选博客 | ||
### B 站 Android 代码库的演进历程 | ||
- [B 站 Android 代码库的演进历程](https://juejin.cn/post/6844903695327428615) | ||
- [如何简单快速搭建 Android 大仓](https://juejin.cn/post/6844903751304773645) | ||
|
||
这篇文章讲述 B 站 Android 代码库的演进历程。从早期的单仓库,到后来的多仓库,再到如今的大仓。单仓库简单但后期有代码混乱和编译慢等问题;多仓库有隔离性等优点,但维护复杂、代码重复等缺点凸显;大仓是单仓库进化版,有工具链辅助。总之,选择方案要适合团队业务,没有通用架构。 | ||
|
||
``` | ||
<root dir> | ||
├── build.gradle | ||
├── settings.gradle | ||
├── app/ | ||
│ ├── app-a | ||
│ │ ├── src | ||
│ │ └── build.gradle | ||
│ ├── app-b | ||
│ │ ├── src | ||
│ │ └── build.gradle | ||
│ ├── build.gradle | ||
│ └── settings.gradle | ||
│ | ||
├── common/ | ||
│ ├── common-a | ||
│ │ ├── src | ||
│ │ └── build.gradle | ||
│ ├── build.gradle | ||
│ └── settings.gradle | ||
│ | ||
├── framework/ | ||
│ ├── lib-a | ||
│ │ ├── src | ||
│ │ └── build.gradle | ||
│ ├── build.gradle | ||
│ └── settings.gradle | ||
│ | ||
└── MyApp | ||
├── src | ||
└── build.gradle | ||
``` | ||
|
||
### [可能是 AGP8 编译最快的方案](https://juejin.cn/post/7432980021121859638) | ||
AGP8 的变更应该很多人都知道了,移除了Transform API,所以很多 class 操作类的插件代码都需要改了。 | ||
|
||
TheRouter在开发的时候就支持了AGP8,使用的是toTransform()这个方法替代老版本的 API,这么做以后有个问题,就是编译速度会非常非常慢,尤其是工程里代码量越大,编译速度越慢。 | ||
|
||
本文提出多种解决思路,如用 AsmClassVisitorFactory 结合 toTransform 或 toGet 方法,TheRouter 还做了内存缓存优化,保障产物结果。 | ||
|
||
```kotlin | ||
project.plugins.withType(AppPlugin::class.java) { | ||
// Queries for the extension set by the Android Application plugin. | ||
// This is the second of two entry points into the Android Gradle plugin | ||
val androidComponents = | ||
project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java) | ||
// Registers a callback to be called, when a new variant is configured | ||
androidComponents.onVariants { variant -> | ||
val taskProvider = project.tasks.register<ModifyClassesTask>("${variant.name}ModifyClasses") | ||
|
||
// Register modify classes task | ||
variant.artifacts.forScope(ScopedArtifacts.Scope.PROJECT) | ||
.use(taskProvider) | ||
.toTransform( | ||
ScopedArtifact.CLASSES, | ||
ModifyClassesTask::allJars, | ||
ModifyClassesTask::allDirectories, | ||
ModifyClassesTask::output | ||
) | ||
} | ||
} | ||
``` | ||
|
||
### [从DDD视角探讨代码复用的成本及效益](https://mp.weixin.qq.com/s/TIJZtzseHqjOFRfUKrjtsQ) | ||
- 类和函数存在的意义困惑:作者从工作经历中对类和函数是否只为复用而产生困惑,随着业务发展,复用的类和函数可能因大量复用和适应不同场景而充满 if...else...,引发对其存在意义的思考。 | ||
- DRY 原则与重复代码的权衡:设计模式的 DRY 原则并非绝对好,在复杂工程中,DRY 的函数被大量引用可能导致逻辑复杂、修改风险高;重复代码反而可能降低后续修改风险,可根据业务需要灵活整合。 | ||
- 复用的成本与效益权衡:复用需要权衡成本与效益。成本包括了解可复用构件、对接接口、测试及排查问题等。效益分为降低开发成本和提升软件产品核心竞争力,如通过整合业务中台快速支撑新业务上线,复用成功模块提升产品竞争力。 | ||
- 深浅模块与复用成本角度:深模块接口简单但功能深刻,复用合算;浅模块接口复杂功能少,复用成本可能高于好处。以文件系统和数据库为例说明深模块的优势,以及项目中浅模块代码的低复用价值。 | ||
- 效益角度谈复用与 DDD 子域划分:从效益角度,复用可提升产品核心竞争力,如 Supercell 游戏公司和钉钉的案例。DDD 对子域划分提供复用策略,核心子域应尽可能复用提升竞争力,支持子域和通用子域根据特点采用不同复用策略。 | ||
- 成功设计与业务理解:强调成功的设计来自对业务问题的深刻理解,DDD 能帮助从业务分析视角看待复用的成本和效益,做出更好的决策。 | ||
|
||
![](https://raw.gitmirror.com/RicardoJiang/resource/refs/heads/main/2024/november/p1.webp) | ||
|
||
![](https://raw.gitmirror.com/RicardoJiang/resource/refs/heads/main/2024/november/p2.webp) | ||
|
||
### [QuickJS的垃圾回收算法](https://mp.weixin.qq.com/s/h0pSSVltIdM0dETI_R_-CA) | ||
文章主要介绍了 QuickJS 的垃圾回收算法,具体内容如下: | ||
|
||
- 常见 GC 算法简介 | ||
- 垃圾评定算法 | ||
- 引用计数法(RC):在对象头添加计数器,记录对象被引用情况,引用时计数器 ++,释放时 --,当计数器为 0 时回收对象,但存在循环引用导致内存泄漏的问题。 | ||
- 可达性分析:以 GC Roots(如当前栈上变量、全局变量等)为起点遍历对象,未被遍历到的为垃圾。 | ||
- 垃圾回收算法 | ||
GC 标记清除法:先通过可达性分析标记存活对象,再清除未标记对象。 | ||
GC 复制算法:将对象分配空间分为两块,申请内存在 from 空间,回收时将存活对象复制到 to 空间,回收 from 空间并交换两块空间身份。 | ||
GC 标记压缩法:前两步同标记清除,之后增加内存整理工作减少碎片。 | ||
分代算法:根据经验将 heap 分为年轻代和老年代,大部分时间只遍历年轻代,多次 GC 未回收的年轻代对象晋升到老年代,内存整体触发阈值时回收整块内存。 | ||
- QuickJS 的垃圾回收算法 | ||
- 引用计数算法(RC)实现:在对象头添加ref_count计数器,创建对象时设为 1,引用时 ++,释放时 --,ref_count<=0 时回收对象。 | ||
- 引用计数的问题:循环引用会导致内存泄漏,如对象 A 引用 B,B 引用 C,C 又引用 A 时,三个对象计数器永远 >=1。 | ||
- QuickJS 解决循环引用的方法:内存上涨触发阈值时,通过JS_RunGC函数执行解环操作,包括遍历gc_obj_list标记对象、处理子对象计数器并将入度为 1 的对象挂到tmp_obj_list,重新遍历恢复标记和计数器,最后回收tmp_obj_list上的对象。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters