WasmSplit.md 12.2 KB
Newer Older
O
migrate  
oceanxiao 已提交
1 2
# 代码分包

S
skyler 已提交
3 4 5 6 7 8 9 10 11 12 13
- [代码分包](#代码分包)
  - [概述](#概述)
    - [背景](#背景)
    - [作用](#作用)
  - [实现原理](#实现原理)
  - [插件使用](#插件使用)
    - [打开分包](#打开分包)
    - [迭代流程](#迭代流程)
    - [关闭分包](#关闭分包)
    - [增量分包](#增量分包)
  - [Changelog](#changelog)
Z
zhangjunkunn 已提交
14 15
    - [v1.1.6](#v116)
    - [v1.1.5](#v115)
S
skyler 已提交
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
    - [v1.1.4](#v114)
    - [v1.1.2](#v112)
    - [v1.1.0](#v110)
    - [v1.0.2](#v102)
  - [FAQ](#faq)
    - [分包是否是必要的](#分包是否是必要的)
    - [收集到什么时候可以结束](#收集到什么时候可以结束)
    - [新增收集的函数要重新再次提审才会在首包吗](#新增收集的函数要重新再次提审才会在首包吗)
    - [会不会最终跑到所有函数都收集的情况](#会不会最终跑到所有函数都收集的情况)
    - [iOS 高性能模式收集很卡](#ios-高性能模式收集很卡)
    - [iOS 高性能模式代码分包后内存反而变得很高](#ios-高性能模式代码分包后内存反而变得很高)
    - [iOS 高性能模式出现 impport section's count is boo big](#ios-高性能模式出现-impport-sections-count-is-boo-big)
    - [没有看到增量分包的界面](#没有看到增量分包的界面)
    - [增量分包没生效](#增量分包没生效)
    - [如何更新分包插件](#如何更新分包插件)
    - [分包插件安装失败](#分包插件安装失败)
    - [内存优化版本未观察到内存优化](#内存优化版本未观察到内存优化)
    - [分包总大小比原始包大](#分包总大小比原始包大)
S
skyler 已提交
34 35 36 37 38 39 40 41 42 43 44 45

## 概述

### 背景

unity 导出小游戏项目后,代码是在一个 wasm 文件里,经过 brotli 压缩后,放在 wasmcode 目录下

一般小游戏的 wasm 大小都为 30M 左右,压缩后为 6M 左右

启动阶段,小游戏需要先下载完 wasmcode 再编译,这里会占用较高的内存和时间

因此我们提供了代码分包工具,将原来的 wasm 拆分为两个,一个用于启动加载,另一个可以延迟加载
S
skyler 已提交
46 47 48

使得小游戏可以先加载较小的首包进入主场景,再异步加载剩下的分包

S
skyler 已提交
49
### 作用
S
skyler 已提交
50 51 52

分包的作用在于优化启动时间

S
skyler 已提交
53
另外对于 iOS 新的高性能模式,分包还有两个作用:
S
skyler 已提交
54

S
skyler 已提交
55
1. 减少内存使用,以支持更多 iOS 低端机上运行高性能模式
S
skyler 已提交
56 57
2. 减少编译时间,降低了游戏前期的发烫情况

S
skyler 已提交
58
## 实现原理
S
skyler 已提交
59 60 61

目前我们采用了一种 Profile Guided Optimization 的方式,通过运行时收集信息,按函数粒度对小游戏的 wasm 代码包进行拆分

S
skyler 已提交
62
开发者可以在离线测试阶段,通过真机运行小游戏,并尽量覆盖游戏内的场景,特别是启动后最先进入的场景和关卡(**比如新手教学,游戏最初的关卡内容**)来收集信息
S
skyler 已提交
63 64 65 66 67

工具上会显示收集到的函数个数,这时候就可以重新分包,将收集到的函数加入首包

因此收集工作非常重要,收集的场景覆盖率越高,命中子包的时机就可以相应延后,使得首包可以满足大部分新玩家前几分钟的游戏进程

S
skyler 已提交
68
## 插件使用
S
skyler 已提交
69 70

我们提供了一个**微信开发者工具**里的**插件**来辅助分包过程,依赖的[开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html)版本为 1.05.2104251 RC 及以上,稳定版 1.05.2105100 已支持
O
migrate  
oceanxiao 已提交
71 72

分包工作流如图所示
S
skyler 已提交
73

O
oceanxiao 已提交
74
<img src="../image/wasmsplit/workflow.png">
O
migrate  
oceanxiao 已提交
75

S
skyler 已提交
76
如图所示,对于未分包项目,开发者可以在插件里启用分包,然后配置版本信息,这时候会插件会自动开始第一次分包,变成已分包项目
O
migrate  
oceanxiao 已提交
77

S
skyler 已提交
78 79
对于已经分包的项目,开发者每次覆盖运行了一些场景,收集到有新增函数个数的时候,就可以生成下一个分包

S
skyler 已提交
80
需要特别注意,**发布的时候要注意使用发布版本**
O
migrate  
oceanxiao 已提交
81

S
skyler 已提交
82
### 打开分包
O
migrate  
oceanxiao 已提交
83

S
skyler 已提交
84
通过开发者工具的设置-拓展设置-编辑器自定义拓展,安装 wasmCodeSplit 这个插件(插件后续 0.0.6 及以下存在部分使用问题,但不影响分包结果,我们会在 0.0.7 修复相关问题)
S
skyler 已提交
85

O
oceanxiao 已提交
86
<img src="../image/wasmsplit/extension-panel.png">
S
skyler 已提交
87 88

### 迭代流程
S
skyler 已提交
89

O
migrate  
oceanxiao 已提交
90
1. 打开插件开关后,在目录树上的工具栏中,可以看到插件的按钮,如图所示,点击后即可进入插件页:
S
skyler 已提交
91
   <img src="../image/wasmsplit/enable-plugin-1.png">
O
migrate  
oceanxiao 已提交
92 93

2. 点击启用代码分包,新导出的小游戏(注:同一游戏从 unity 的不同次导出也认为是新的)会提示输入版本描述,简单输入方便识别版本的描述即可,然后插件会自动进行首次分包
S
skyler 已提交
94 95
   <img src="../image/wasmsplit/enable-plugin-2.png">
   <img src="../image/wasmsplit/start-split.png">
O
migrate  
oceanxiao 已提交
96 97 98

3. 第一次分包完成后,就可以开始迭代式收集,每一轮迭代流程如下:

S
skyler 已提交
99 100 101
第 1 步:android 收集

第 2 步:iOS 收集
S
skyler 已提交
102

S
skyler 已提交
103
第 3 步:可以选择再来一轮或者生成发布版本
S
skyler 已提交
104

S
skyler 已提交
105
1,2 步里的收集过程:
S
skyler 已提交
106

O
migrate  
oceanxiao 已提交
107
- 点击开发者工具的预览,在真机上跑,有条件的话可以尽量覆盖各种机型(主流品牌)以及平台(Android/iOS)
S
skyler 已提交
108
- 当插件页显示的收集到增量函数个数相对稳定时,可以点击“我已收集好,继续下一步”
O
migrate  
oceanxiao 已提交
109

O
oceanxiao 已提交
110
<img src="../image/wasmsplit/code-split-index.png">
O
migrate  
oceanxiao 已提交
111

S
skyler 已提交
112
随着迭代轮数增多,新增函数会越来越少,这里没有完成收集的标准,建议开发者能回归覆盖游戏的各种启动场景即可(不同进度,二次启动等等),目的是为了延迟依赖剩下的分包的时间
O
migrate  
oceanxiao 已提交
113

S
skyler 已提交
114
**注意:**
O
migrate  
oceanxiao 已提交
115

S
skyler 已提交
116 117
- 分包过程中尽量不要对小游戏项目进行编辑,开发者工具上的 console 报错也可以忽略,等分包完成后回到上图界面再操作
- 在第一次进入 iOS 分包之前,需要对代码包做预处理,这里预计需要等待 10-30 分钟
O
migrate  
oceanxiao 已提交
118

S
skyler 已提交
119
### 关闭分包
O
migrate  
oceanxiao 已提交
120

S
skyler 已提交
121
如果想回退到未分包的版本,点击插件页的关闭代码分包按钮即可
S
skyler 已提交
122 123 124

### 增量分包

S
skyler 已提交
125
从 unity 每一次导出后的小游戏,都需要重新分包,对于小版本改动会产生比较烦人的工作量
S
skyler 已提交
126 127 128

因此我们支持了增量分包,可以在二次导出时,通过选择之前已经进行过分包的版本,在之前分包的基础上进行增量分包

O
oceanxiao 已提交
129
<img src="../image/wasmsplit/incremental-split.png">
S
skyler 已提交
130

S
skyler 已提交
131
这里主要是通过 symbol 文件,按函数签名识别相同函数来实现的,因此需要导出时有 symbol 文件
S
skyler 已提交
132

Z
zhangjunkunn 已提交
133
## Changelog
Z
zhangjunkunn 已提交
134

Z
zhangjunkunn 已提交
135 136 137 138 139 140 141 142 143
### v1.1.6
#### Changed
- 移除无用代码

### v1.1.5
#### Fixed
- iOS普通模式无法进入游戏
- 安卓微信客户端8.0.25无法进入游戏

S
skyler 已提交
144
### v1.1.4
Z
zhangjunkunn 已提交
145
#### Fixed
S
skyler 已提交
146 147
- 修复iOS profile版在高性能模式下卡与内存不足的问题
- 修复android偶现`null function or function signature mismatch`问题
S
skyler 已提交
148
- 修复iOS普通模式运行出错的问题
S
skyler 已提交
149 150

### v1.1.2
Z
zhangjunkunn 已提交
151
#### Changed
S
skyler 已提交
152 153
- 插件新旧版本分包兼容

Z
zhangjunkunn 已提交
154
### v1.1.0
Z
zhangjunkunn 已提交
155
#### Added
Z
zhangjunkunn 已提交
156 157
- iOS高性能内存优化:
  - 使用条件:**转换插件版本高于202212070000****重新导出**
Z
zhangjunkunn 已提交
158
- 分包插件交互优化
Z
zhangjunkunn 已提交
159
  - 等待预处理提前到选择是否增量更新的界面,收集时可使用安卓和iOS同时进行
Z
zhangjunkunn 已提交
160 161 162 163
  - 收集界面增加连接状态、appid信息展示


### v1.0.2
Z
zhangjunkunn 已提交
164
#### Added
Z
zhangjunkunn 已提交
165
- 包体优化&广告买量启动优化
Z
zhangjunkunn 已提交
166 167 168
  - 使用条件:**转换插件版本高于202212070000导出的包**


S
skyler 已提交
169
## FAQ
S
skyler 已提交
170

S
skyler 已提交
171
### 分包是否是必要的
S
skyler 已提交
172

S
skyler 已提交
173
---
S
skyler 已提交
174

S
skyler 已提交
175
对于 iOS 高性能模式,由于内存限制,游戏加载完整 wasm 基本就会内存 crash。分包能降低内存占用,同时我们对子包支持按需加载,才让游戏能稳定跑起来
S
skyler 已提交
176

S
skyler 已提交
177
所以如果是使用了 iOS 高性能模式则是必须的
S
add faq  
skyler 已提交
178

S
skyler 已提交
179
对于 android 和 iOS 普通模式,分包主要目的是优化启动加载,另外这两个 runtime 下由于子包可以全量加载,因此对游戏运行影响最多只有加载子包的一次性影响
S
add faq  
skyler 已提交
180

S
skyler 已提交
181
我们也会在启动 callmain 后 30s 提前加载子包,在这个时间之后才触发未收集函数的情况也不会有加载子包的影响
S
add faq  
skyler 已提交
182

S
skyler 已提交
183
### 收集到什么时候可以结束
S
add faq  
skyler 已提交
184

S
skyler 已提交
185
---
S
add faq  
skyler 已提交
186

S
skyler 已提交
187
按照我们经验,一般首包函数有整包个数的 33%以上的时候就可以接受了,当然能尽量再收集完善刚好,个别游戏可能会接近 50%
S
add faq  
skyler 已提交
188 189 190

这时候不代表没收集的函数都没用了,实际上有些函数可能只是调用比较冷门,后续还是可能会被调到,可以通过分包插件面板的`新增收集函数个数`来留意线上新增的情况,

S
skyler 已提交
191
如果线上新增较多(超过 50),可以考虑再往下分一次包然后提审发布
S
add faq  
skyler 已提交
192

S
skyler 已提交
193 194 195
### 新增收集的函数要重新再次提审才会在首包吗

---
S
add faq  
skyler 已提交
196 197 198

对的,用户下载的代码包只能是提审发布过的

S
skyler 已提交
199 200 201
### 会不会最终跑到所有函数都收集的情况

---
S
add faq  
skyler 已提交
202

S
skyler 已提交
203
目前还没出现这种情况,超过整包 50%的都很少
S
add faq  
skyler 已提交
204

S
skyler 已提交
205
大部分游戏收集 1 小时的函数个数都在 33%到 50%之间
S
add faq  
skyler 已提交
206

S
skyler 已提交
207
可以等收集函数超过 75%了再来考虑这个问题
S
add faq  
skyler 已提交
208

S
skyler 已提交
209
### <p id="ios-high-performance-lag-when-profiling">iOS 高性能模式收集很卡</p>
S
add faq  
skyler 已提交
210

S
skyler 已提交
211
---
S
add faq  
skyler 已提交
212

S
skyler 已提交
213
iOS 高性能模式由于加载子包的实现不同,刚开始收集时又基本是跑子包函数,所以最开始的收集会比较卡
S
add faq  
skyler 已提交
214

S
skyler 已提交
215
这个时候可以观察分包插件面板,如果能看到有新增函数个数的变化,一般就是没问题的。如果出现卡顿(并且有新增函数)或者新增函数较多(超过 50),可以先继续往下生成分包,再进行收集。游戏运行会随着收集越来越流畅
S
add faq  
skyler 已提交
216

S
skyler 已提交
217
### <p id="ios-high-performance-more-memory">iOS 高性能模式代码分包后内存反而变得很高</p>
S
skyler 已提交
218

S
skyler 已提交
219 220 221 222
---

这种情况一般是太多新增函数(比如几百个),iOS 高性能模式的子包代码也会占用大量内存,可以继续生成分包,将这部分函数放在首包(放首包的内存占用相对小些)

S
skyler 已提交
223
### <p id="ios-high-performance-import-section-too-big">iOS 高性能模式出现 impport section's count is boo big</p>
S
skyler 已提交
224 225 226 227 228 229 230 231 232 233 234 235

---

这个是 iOS 上的限制,一般需要子包控制在 10w 个函数以内

子包函数个数 = 原始包函数总个数 - 当前首包函数个数,可以从分包插件面板看到

出现超出的情况时,可以对游戏代码进行裁剪(如删掉没用到的插件),或者用 android 多收集一些

### 没有看到增量分包的界面

---
S
skyler 已提交
236 237 238

由于增量分包是新增的功能,因此之前的项目不能被用来增量更新。更新分包插件后,第二次导出的版本开始才可以使用

S
skyler 已提交
239 240 241 242 243
### 增量分包没生效

---

请检查指定参考的旧版本以及当前版本是否都有 symbol 文件,以及是否有更换引擎或者其他导致代码变动较大的操作
Z
zhangjunkunn 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262

### 如何更新分包插件

---

微信开发者工具会自动更新分包插件,一般不需要手动更新。可前往**微信开发者工具-编辑器区域-拓展列表**查看插件版本确认是否为最新版本

> 请勿使用小游戏版微信开发者工具,会出现插件无法正常更新或安装。请前往:适配文档-安装与使用,下载stable版本微信开发者工具。

<image src="../image/wasmsplit/check-version.png">

### 分包插件安装失败

---

**首先确认是否为stable版本开发者工具。**

有两个地方可安装插件:
1. 编辑器区域-拓展:搜索wasm-code-split,点击安装
S
skyler 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
2. 菜单栏-设置-拓展设置,找到wasmcodesplit,点击进入详情页,点击获取

### 内存优化版本未观察到内存优化

---
1. 首先排查项目是否已经是内存优化版本的分包:插件面板当前后台服务版本为3(或者看framework最后的API_VERSION)
2. 这里的内存优化主要针对iOS高性能模式,主要是减少了编译相关的内存(和函数个数相关,10w+函数的包可以减少约100M),可以通过在callmain或者raf之前暂停来观察
3. 最终到游戏内有可能会上涨到和原来差不多,但这个是受gc策略和系统进程内存优化的影响,可以点右上角退出小游戏触发强制gc来观察

### 分包总大小比原始包大

---
1. 分包的目的主要是将启动时需要的包减小,一般分包后wasm首包可以控制在原包的1/3到1/2之间
2. 子包是有延迟加载的,因此耗时上不需要看总的大小,看首包的减少量即可
3. 一般iOS高性能模式才有内存使用瓶颈,而iOS上子包是按需加载的,可以缓解内存问题
S
skyler 已提交
278
因此,这里不需要关注分包后所有wasm包的总和,主要关注wasm首包(即minigame/wasmcode)的大小即可