Skip to content

Commit

Permalink
更新内存优化指引
Browse files Browse the repository at this point in the history
  • Loading branch information
Oooocean committed Nov 30, 2021
1 parent 3a6c006 commit 4dec84c
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 5 deletions.
99 changes: 99 additions & 0 deletions Design/OptimizationMemory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# 优化Unity WebGL的内存
## 一、内存与OOM
Unity WebGL游戏通常比普通H5(JS)游戏占用更大的内存,在操作系统的控制策略下超出阈值时非常容易被OOM。

为了提高游戏在中低端机型的稳定性,内存优化极为重要。那么,多大的内存是合理的呢?
我们建议内存峰值控制在以下范围:
1. Android: 低档机 < 1.2G, 中高档机 < 1.5G
2. iOS: 低档机 < 1G, 中高档机 < 1.4G

相对而言,Android机型的内存更为宽松。

iOS低档机为iPhone 6sp/7/8等2G机型为主,中高档机为iPhone 7P/8P/iPhoneX/iPhone11等。



## 二、Unity WebGL适配小游戏的内存结构
Unity WebGL内存结构可先参考:

[Unity博客:了解 Unity WebGL 中的内存 (Understanding Memory in Unity WebGL)](https://blogs.unity3d.com/2016/09/20/understanding-memory-in-unity-webgl/?_ga=2.221731928.1756133398.1638172136-1917727044.1634213664)

[Unity博客:Unity WebGL 内存:Unity 堆 (Unity WebGL Memory: The Unity Heap)](https://blog.unity.com/technology/unity-webgl-memory-the-unity-heap)

<image src='../image/optimizationMemory1.png' width="1080"/>
Unity WebGL是以WebAssembly+WebGL技术为基础的应用,运行在浏览器环境,因此游戏内存的分配也是完全托管在这个环境中。

适配在小游戏后,小游戏进程也就成为了容器,虽然不再是标准的浏览器,但内存组成结构与上图基本一致。以下是小游戏环境的注意事项:

- DOM:浏览器页面元素,Cavas等。在小游戏环境中并不存在DOM,但依然会存在一些基本消耗,比如小游戏公共库,Canvas画布等。典型地,***小游戏公共库约占用内存100~150MB,Canvas 画布与设备物理分辨率相关***,比如iPhone 11 Promax占用约80MB。

- Unity Heap: 用于存储所有状态、托管的对象和本机对象以及当前加载的资源和场景的内存。举例,游戏逻辑分配的C#对象等托管内存,以及Unity管理的AssetBundle对象、场景结构等本机内存。一般情况下建议200MB左右为宜,***不要超过300MB,切忌产生跳跃峰值***

- Asset Data: 原生APP通常不会有这类内存,AssetData需要文件的同步读写能力,但浏览器环境并不支持。Emscripten使用[文件系统](https://emscripten.org/docs/api_reference/Filesystem-API.html)模拟Linux/POSIX接口,***代价是占用与文件同等大小的内存***

- AssetBundles: 上图的AssetBundles指的是下载时产生WebHttpRequest的临时内存,并非AB在Native内存的占用。***当包体较大或网络并发较大时,下载容易产生内存峰值,虽然为临时内存缺很可能突破OOM阈值导致Crash***

- WebAudio:Unity将音频传递给容器(浏览器或小游戏)后,播放音频时将占用的内存。目前自带音频系统存在较大内存和性能问题,Unity2021之前不支持内存压缩音频,因此音频加载后将被完整解压,***非压缩音频会导致极大内存占用***

- Memory File System: 由于Emscripten的[文件系统](https://emscripten.org/docs/api_reference/Filesystem-API.html)。除了前面提到的Asset Data外,任何需要File.Read/Write同步操作的数据都将占用内存,***通常包括:首资源包、Addressable Cache机制、WWW.LoadFromCacheOrDownload等Cache API。开发者不应使用此类接口。***

- Comiled Code: WebAssembly需要编译,在Android v8、iOS JavascriptCore中还需要大量内存进行JIT优化,***开发者应减少非必要第三方插件,使用代码分包能力进行内存控制***


## 三、内存查看工具
开发者可由系统进程、JavaScript Heap等方面去分析和查看游戏内存。

### 3.1 进程总内存
查看总内存时,我们需要先确定监控的小游戏进程名称:
- Android:WeChat AppBrand1/2
- iOS:普通模式WeChat、高性能模式(WebContent)
#### Instruments in Xcode(iOS)
<image src='../image/optimizationMemory2.png' width="1080"/>
使用Activity Monitor,选择对应的设备-all processes-捕捉,即可看到所有进程的CPU与内存情况.
<image src='../image/optimizationMemory3.png' width="1080"/>

#### Perfdog(Android or iOS)
使用[Perfdog](https://perfdog.qq.com)选择对应的设置-进程名,即可看到相关性能数据,iOS设备应以紫色的XcodeMemory为准。
<image src='../image/optimizationMemory4.png' width="1080"/>

### 3.2 JavaScript Heap
由于Unity WebGL是托管在浏览器环境中,因此JavaScript Heap包含了大部分(并非全部)我们关注的内存, 通常我们可以使用浏览器自带的内存工具。
#### FireFox Memory(PC)
#### iOS Safari Timeline(PC or iOS)
<image src='../image/optimizationMemory5.png' width="1080"/>

### 四、内存优化方案
以iOS为例,一款代码大小为30MB的游戏占用内存为:
小游戏基础库(130MB) + Cavnas(70MB) + 编译内存(300MB) + Unity Heap(托管内存 + Native内存) + Gfx显存 + 音频 + 胶水层。

假如游戏需要支持低档机型,将内存控制到1G以内,业务侧(Unity Heap, Gfx显存,音频,胶水层)需控制在500MB左右。我们此处给出转换游戏中最容易遇到的内存问题与解决方案,如果开发者遇到内存问题时请逐个排查优化。


### 4.1 WebAssembly编译代码内存
- 问题原因:Unity WebGL将所有代码(引擎、业务代码、第三方插件)编译WebAssembly,运行时需进行编译。在部分系统如iOS,此部分内存占用非常大(如30MB未压缩代码需300MB运行时编译内存)。
- 解决办法:[使用代码分包工具](Design/WasmSplit.md)能降低原编译代码内存50%以上。

### 4.2 GPU纹理内存
- 问题原因:Unity 2021才开始支持移动平台的压缩纹理,使用RGBA、DXT等纹理格式将导致巨大的内存开销与运行时解压消耗。
- 解决办法:[压缩纹理优化](Design/CompressedTexture.md)能最大程度地减少内存与解压开销。


### 4.3 Unity Heap
- 问题原因:Unity Heap是用于存储所有状态、托管的对象和本机对象,往往由于场景过大或由于业务原因造成瞬间内存峰值。***请切记,Heap是只增不减且存在内存碎片的。***
- 解决办法:避免同一时刻使用过多内存,比如场景过大、AssetBundle体积太大、单帧分配的对象过多等内存峰值。


### 4.4 首资源包与AssetBundle内存
- 问题原因:首资源包永远占用内存且无法释放;首资源包和AssetBundle自带的cache机制都会使用Emscripten使用[文件系统](https://emscripten.org/docs/api_reference/Filesystem-API.html),应避免使用。
- 解决办法:1. 减少首资源包大小,此部分始终占用内存无法释放, 使用AssetBundle;
2. AssetBundle按需加载,及时释放以节省内存;
3. AssetBundle使用时被解压占用Unity Native内存,应减少AssetBundle大小;
4. 避免使用Unity自带的文件缓存机制, ***首资源包和AssetBundle都不应使用文件Cache***

### 4.5 音频内存
- 问题原因:Unity2021之前不支持内存压缩音频,因此音频加载后将被完整解压,***非压缩音频会导致极大内存占用***
- 解决办法:使用小游戏SDK[音频适配优化](Design/AudioOptimization.md)

## 五、QA
1. 在Unity Profiler看到内存才200MB+,是否代表游戏内存无问题
不是。游戏占用内存必须以真机环境为准,使用Perfdog(Android or iOS)或 Instruments in Xcode(iOS)测试对应进程的内存占用。Unity Profiler仅能看到Unity Heap相关内存,并不包含小游戏公共库、Cavas、WebAssembly编译以及容器其他内存。
7 changes: 4 additions & 3 deletions Design/ShowCase.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
Unity制作的[
EndlessRunnerSampleGame](https://github.com/Unity-Technologies/EndlessRunnerSampleGame)的小游戏适配。 一款有趣的跑酷类游戏,控制一条勇敢的街头猫,沿着一个大城市的街道跑步,沿途收集鱼骨和沙丁鱼罐头,同时避开各种致命的障碍和怪物。

## 网吧模拟器
## 我叫MT2

<image src='../image/showcase1.png' width="200"/>
<image src='../image/showcase24.png' width="200"/>

由成都品游科技有限公司(Papa Box)开发的模拟经营向的游戏。一款挂机模拟经营类的休闲游戏。玩家将会作为一名网吧老板誓要濒临破产的网吧经营为一个奢华的网咖,玩家需要通过宣传推广,购置机器,雇佣员工等手段将网吧做大做强。
## 我叫MT2
由乐动卓越研发的精美3D手游,延续了传统《我叫MT》的经典特色。钓鱼挖矿,外域探险玩法都将为您呈现独一无二的掌中魔幻世界!

## 就差一刀

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@


## 转换案例
| 地铁跑酷 | 网吧模拟器 | 翡翠大师小游戏 | 就差一刀 |
| 地铁跑酷 | 我叫MT2 | 翡翠大师小游戏 | 神枪手杰克 |
| --- | --- | --- | --- |
| <image src='image/showcase23.png' width="230"/> | <image src='image/showcase1.png' width="200"/> | <image src='image/showcase8.png' width="200"/>| <image src='image/showcase7.png' width="200"/> |
| <image src='image/showcase23.png' width="230"/> | <image src='image/showcase24.png' width="200"/> | <image src='image/showcase8.png' width="200"/>| <image src='image/showcase13.png' width="200"/> |

- [更多转换案例](Design/ShowCase.md)

Expand Down Expand Up @@ -51,6 +51,7 @@
- 运行性能
- [使用 Android CPU Profiler 性能调优](Design/AndroidProfile.md)
- [使用 Unity Profiler 性能调优](Design/UnityProfiler.md)
- [优化Unity WebGL的内存](Design/OptimizationMemory.md)
- [音频适配优化](Design/AudioOptimization.md)
- [压缩纹理优化](Design/CompressedTexture.md)
- [资源优化工具与建议](Design/AssetOptimization.md)
Expand Down
Binary file added image/optimizationMemory1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added image/optimizationMemory2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added image/optimizationMemory3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added image/optimizationMemory4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added image/optimizationMemory5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added image/showcase24.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 4dec84c

Please sign in to comment.