Unity 3D MMO RPG手游征服2GB设备之历程

文章目录

项目背景

场景

  • 1024*1024
  • 同屏200W面
  • 贴图1024
  • 自由视角

配置表

  • 1000+张配置表
  • C++内存加载350MB

角色

  • 同屏20人
  • 45个职业变种
  • 数万件时装
  • 模型面数3-5W面

业务系统

  • 3000+个界面
  • 200W+行非生成代码

资源

  • 10W+个AB

Unity版本

  • 2019

内存分布

  • Native Heap
  • Code
  • Graphic 图形内存
  • Unknown

Native Heap

Native Heap用来存放 C++层(引擎层) 的各种对象和资源数据。

  • Unity Engine 内部结构体、组件对象
  • 资源(Texture、Mesh、AudioClip 等)的 CPU 端数据
  • NativeContainer(如 NativeArray、NativeList 等)
  • Job System / Burst 编译代码用到的临时缓冲区
  • 底层系统调用(如物理系统、导航系统、动画系统)

Unknown

  • 华佗HybridCLR热更新的元数据

定位工具

Native内存

环境配置

  • Android Studio
  • Profile
  • Record Native Allocation

Code内存

环境配置

  • Android Studio
  • adb shell
  • run-as com.Unity.ClassicSponza cat /proc/11810/maps | grep libil2cpp.so

Lua内存

  • 递归遍历

关键指标

  • Native内存: 200MB
  • C++配置表: 30-40MB
  • Graphic: 100MB
  • Code: 100MB
  • Mono: 100MB
  • UnityNative: 200MB
  • 总计750MB

常见优化手段

纹理贴图

  • 图集
  • ASTC压缩
  • 关闭mipmap
  • 九宫格
  • 对称
  • 单行渐变
  • 单通道贴图
  • 关闭ReadWrite
  • 合理分辨率设置
  • 超采样压缩
  • streamingmipmap

模型

  • LOD
  • 优先级显示
  • 剔除余通道
  • 关闭ReadWrite
  • 名字版替代

场景

  • 公告板
  • LOD
  • 流式加载
  • 分层显示
  • 光照探针优化光照

特效

  • 贴图256
  • 总数限制
  • 粒子最大数量限制
  • LOD加载
  • 去重
  • 模型最大顶点数限制

动画

  • 压缩格式
  • 骨骼剔除
  • 属性剔除
  • 曲线压缩

音频

  • 压缩格式设置
  • 单通道
  • streaming
  • lazy加载

字体

  • 静态图集
  • 动态图集
  • ttf剔除

Shader

  • 变体剔除

优化案例

Mono内存

  • 去除字符串
  • gc替代缓存
  • 数据转移C++
  • 精简数据结构
  • 延迟加载
  • 精准卸载

代码元数据优化(Metadata)

IL2CPP在使用到某个类型时,会初始化这个类型完整的元数据,包括它的所有函数、接口、事件、属性、虚函数表等,并且一旦加载后就不会再释放。所以一个MMO游戏中,充分运行后,代码元数据占用的内存会非常高。

  • 排查泛型Template用的是否较多
  • 排查自动化生产的代码是否较多
  • 排查Lua生产的Wrapper代码是否较多
  • 删除无用插件、代码
  • 排查IL2CPP是否进行裁剪
  • 代码裁减调整至最高等级
  • link.xml

团结引擎通过深入分析,脚本代码实际运行时,通常只会用到很少的一部分元数据(反射、或者虚函数调用时访问)。例如,一个数组类型可能包含155个方法和25个虚函数,实现了6个接口,但实际运行时可能只会用到其中一小部分,导致大量内存被余加载。

因此,可以采用延迟加载策略。这意味着只有当游戏真正需要某个元数据项时,才会初始化和加载该数据。这种方法可以显著减少IL2CPP运行时的内存占用。

Unity后处理

  • 修改Urp的渲染管线,动态开关渲染特性,渲染特性的资源动态分配&释放
  • 重写后处理的框架,内存相关优化代码结构,避免反射进行无效访问
  • 动态加卸载用到的资源

配置表

背景

  • 1000张配置表
  • 内存占用极高
  • C#/Lua频繁访问

可选方案

  • 存储在单侧Lua/C#
  • 混合存储
  • C++存储

方案选择

  • 配置表全部放到C++
  • 生成lua config wrap文件
  • 生成c# config wrap文件
  • 弱表
  • 支持强引用
  • C++内存压缩

优势

  • C#/lua访问C++非常高效
  • 全局只有一份,配置数据零余
  • 内存占用更低
  • 代码结构更优

C++内存压缩

压缩方法

  • 对象池,合并重复单元格
  • 位运算,优化列数据量
  • int8替代指针引用
  • mmap文件映射
  • 数据结构优化
  • 延迟加载
  • ...

场景流式加载

背景

  • 1024*1024
  • 同屏200W面
  • 贴图1024
  • 自由视角

美术资产分类

  • 微景,装饰物,不影响游戏内容,比如碰撞,导航
  • 近景,小型建筑物
  • 中景,房屋建筑
  • 远景,地形,轮廓,特色标志性建筑

加载策略

  • 格子加载
  • 分层加载
  • 连通图加载
  • 自适应加载
  • 全局LOD加载

总结

  • 精准定位,杜绝主观猜测
  • 深入分析,精通业务
  • 全量优化,不放过任何一个模块
  • 逐个攻克,没有捷径
相关推荐
jump_jump3 小时前
流式 HTML:从 htmx 片段装配到浏览器原生增量渲染
javascript·性能优化·前端工程化
小小工匠1 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
大鱼>1 天前
地平线BPU部署实战:YOLOv8在J5/X3上的算法适配与性能优化
算法·yolo·性能优化
醉颜凉1 天前
Elasticsearch高性能优化:Bulk API大规模数据导入性能调优全攻略
elasticsearch·性能优化·jenkins
叶帆1 天前
【YFIOs】用C#开发硬件之设备上云
开发语言·unity·c#
隔窗听雨眠1 天前
C语言函数递归从入门到精通(下):性能优化与工程实践
c语言·算法·性能优化
探物 AI1 天前
【3D·感知】从PointNet到PointPillars:如何让自动驾驶汽车“实时“看见3D世界?
3d·自动驾驶·汽车
久数君1 天前
AI三维建模工具“造形家”:地理场景三维化的高效解决方案
unity·glb·ai算法·ai三维建模工具·地图框选·造形家·城市建筑模型
苏州邦恩精密1 天前
GOM三维扫描在制造中的真实价值:让“修模”从经验动作变成数据动作
人工智能·科技·机器学习·3d·自动化·制造
昇腾CANN1 天前
【cann-samples系列】GroupedMatmul MX量化矩阵乘的深度性能优化实践
线性代数·性能优化·矩阵·昇腾·cann