浅谈Unity内存模型(一)
一. 内存指标[*]Resident Set Size(RSS): 应用实际使用的物理内存+应用依赖的共享库内存
[*]Unique Set Size(USS): 应用实际使用的物理内存
[*]Proportional Set Size(PSS): 应用实际使用的物理内存+均摊后的共享库内存 一般来说,游戏开发者最关注的是USS或PSS内存。
二. 分配方式
[*]Native Mem
[*]AssetData: Textures,AudioClips,Meshes
[*]Game Objects & Components: Transforms, etc
[*]Engine Internals: Managers,Rendering,Physics,etc
[*]Managed Mem(托管内存)
[*]Scripts Object (reference type)
[*]Unity Wrappers objects 注意, Unity Editor下和Runtime的分配方式和内存大小可能都不同, 所以测性能尽可能要在真机上测试
三. Unity Native内存管理
[*]有兴趣的可以看一下高川大佬在Unite的演讲 https://www.bilibili.com/video/BV1aJ411t7N6
[*]如何优化Native内存
[*]关注Scene内存
[*]关注Audio
[*]DSP Buffer(大小设置合适、降低默认声音质量)
[*]Force to Mono(默认不要双声道)
[*]Format
[*]Compression Format选型
[*]Code Size
[*]注意不要滥用泛型,IL2CPP会把泛型按类型展开
[*]AssetBundle
[*]TypeTree。TypeTree 当确定使用的Unity版本和BuildAssetBundle 及 BuildApk 的Unity版本一致时,可以选择关闭TypeTree,避免为了兼容不同版本增加类型数据。关闭这个会提升反序列化效率以及减小内存
[*]LZ4. LZ4比LZMA压缩包体体积大30%,但速度快10倍,并且分块解压,会减少内存峰值。总之强推LZ4
[*]Size&Count. 要学会trade-off,AB包Size过大内存占用高,Size过小会让头数据重复内存占用也会高(而且DrawCall可能会爆炸)。官方2019年时的推荐值为1M~2M,现在可以适当加大。而且考虑到其他系统的效率笔者建议在这基础上优先要考虑一个AB存储内容的相关性。
[*]Resources 文件夹
[*]Unity内部会为了方便访问维护一个红黑树. 该RBTree常驻且在游戏运行前分析完毕,不建议大规模使用
[*]Texture
[*]不要开w/r: 会在显存内存中各一份
[*]UI不要开MIPMAP,省33.3..%
[*]关注压缩格式。目前来说移动端ASTC最优且品质可调
[*]关注图集分配
[*]Mesh
[*]compression
[*]如何优化托管内存
[*]VM内存池
[*]当一个Block连续6次GC没有被访问到会被返回给系统,比较难触发。
[*]GC
[*]没有分代的(扫描慢)。从根节点全部扫描一遍
[*]Mark-Sweep的(会有内存碎片问题)。只是标记清除而没有进行压缩操作
[*]保守(不能精确地识别垃圾)的GC。可能会将一个int值识别为地址去标记。精确GC会记录每一次分配的地址,能够知道什么数据是一个地址。
Unity内存最佳实践
[*]好的C#程序员会善用Struct(快且不用GC),坏的C#程序员永远class一把梭
[*]池中池。构建更加贴合具体模块的内存池(如UI系统、Particle等)
[*]少用闭包和匿名函数!底层会转化成一个匿名的class,这个内存很细小很容易在Unity中产生碎片化问题。很容易变成僵尸内存又频繁GC
[*]协程一定要有开有关!在MonoBehavior的生命周期中只要协程没被释放,状态就会一直在内存中存着(即使是局部变量)
[*]配置表优化。配置表数据请不要全加载进内存!可以采用树形加载等方式
[*]单例。想一想你真的需要一个单例吗?
[*]可否用静态类、服务选择器代替呢?也许你的”Manager“只需要一个提供静态方法的类
[*]可否不提供全局访问只维持单一实例呢?
[*]可否使用服务定位器、依赖注入等方式来实现你的框架?
[*]如果不是框架级的代码,个人建议禁止使用常驻单例
参考
https://www.bilibili.com/video/BV1aJ411t7N6 [赞同]学到了
页:
[1]