《Unity挪动端游戏性能优化简谱》从Unity挪动端游戏优化的一些根底探讨登程,例举和剖析了近几年基于Unity开发的挪动端游戏我的项目中最为常见的局部性能问题,并展现了如何应用UWA的性能检测工具确定和解决这些问题。内容包含了性能优化的根本逻辑、UWA性能检测工具和常见性能问题,心愿能提供给Unity开发者更多高效的研发办法和实战经验。

明天向大家介绍文章第二局部:资源内存、Mono堆内存等常见游戏内存管制,共13大节,蕴含了纹理资源、网格资源、动画资源、音频资源、材质资源等多个资源内存以及Mono堆内存等常见的游戏内存管制解说。
(全文长约11400字,预计浏览工夫约20分钟)

文章第一局部《Unity挪动端游戏性能优化简谱之 前言》可戳此回顾,残缺内容可返回UWA学堂查看。

1. 总览

1.1 概念解释
首先,在探讨内存相干的各项参数和制订规范之前,咱们须要先理清在各种性能工具的统计数据中常呈现的各种内存参数的理论含意。

在安卓零碎中,咱们最常见到和关怀的PSS(Proportional Set Size)内存,其含意为一个过程在RAM中理论应用的空间地址大小,即理论应用的物理内存。就后果而言,当一个游戏过程中PSS内存峰值越高、占以后硬件的总物理内存的比例越高,则该游戏过程被零碎杀死(闪退)的概率也就越高。

而在PSS内存中,除了Unused局部外,咱们个别比较关心Reserved Total内存和Lua、Native代码、插件等零碎缓存、第三方库的本身调配等内存。Reserved Total占比个别较高,故其大小和走势,也是UWA性能剖析工具的次要统计对象(对于应用到Lua的我的项目,UWA另外提供了Lua专项测试报告统计Lua内存,下文还会提到)。

Reserved Total和Used Total为Unity引擎在内存方面的总体调配量和总体使用量。 一般来说,引擎在分配内存时并不是向操作系统 “即拿即用”,而是首先获取一定量的间断内存,而后供本人外部应用,待空余内存不够时,引擎才会向零碎再次申请一定量的间断内存进行应用。

留神:对于绝大多数平台而言,Reserved Total内存 = Reserved Unity内存 + GFX内存 + FMOD内存 + Mono内存

(1) Reserved Unity内存
Reserved Unity和Used Unity为Unity引擎本身各个模块外部的内存调配,包含各个Manager的内存占用、序列化信息的内存占用和局部资源的内存占用等等。

通过针对大量我的项目的深度剖析,UWA发现导致Reserved Unity内存调配较大的起因次要有以下几种:

序列化信息内存占用:Unity引擎的序列化信息品种繁多,其中最为常见且内存占用较大的为SerializedFile。该序列化信息的内存调配次要是我的项目通过特定API(WWW.LoadFromCacheOrDownload、CreateFromFile等)加载AssetBundle文件所致。

资源内存占用:次要包含Mesh、AnimationClip、RenderTexture等资源。对于未开启“Read/Write Enable” 选项的Mesh资源,其内存占用是统计在GFX内存中供GPU应用的,但开启该选项后,网格数据会在Reserved Unity中保留一份,便于我的项目在运行时对Mesh数据进行实时的编辑和批改。同时,如果研发团队同样开启了纹理资源的 “Read/Write Enable” 选项(默认状况下为敞开),则纹理资源同样会在Reserved Unity中保留一份,进而造成其更大的内存占用。

(2) GFX内存
GFX内存为底层显卡驱动所反馈的内存调配量,该内存调配由底层显卡驱动所管制。一般来说,该局部内存占用次要由渲染相干的资源量所决定,包含纹理资源、Mesh资源、Shader资源传向GPU的局部,以及解析这些资源的相干库所调配的内存等。

(3) 托管堆内存
托管堆内存示意我的项目运行时代码调配的托管堆内存调配量。对于应用Mono进行代码编译的我的项目,其托管堆内存次要由Mono调配和治理;对于应用IL2CPP进行代码编译的我的项目,其托管堆内存次要由Unity本身调配和治理。

1.2 内存参数规范
在咱们理解了内存相干的各项参数的含意之后,晓得了防止游戏闪退的重点在于管制PSS内存峰值。而PSS内存的大头又在于Reserved Total中的资源内存和Mono堆内存。对于应用Lua的我的项目来说,还应关注Lua内存。

依据UWA的教训,只有当PSS内存峰值管制在硬件总内存的0.5-0.6倍以下的时候,闪退危险才较低。举例而言,对于2GB的设施而言,PSS内存应管制在1GB以下为最佳,3GB的设施则应管制在1.5GB以下。

而对于大多数我的项目而言,PSS内存大概高于Reserved Total 200MB-300MB左右,故2GB设施的Reserved Total应管制在700MB以下、3GB设施则管制在1GB以下。

特地的,UWA还认为Mono堆内存须要予以关注,因为在很多我的项目中,Mono堆内存除了存在自身驻留偏高或存在泄露危险的问题外,其大小还会影响GC耗时。UWA认为管制在80MB以下为最佳。

下表为UWA提供的细化到每一种资源内存的举荐规范,制订较为严格。不过,仍须要开发者依据本身我的项目的理论状况予以调整。比方某个2D我的项目节俭了简直所有网格资源的应用,那么其余资源的规范就能够放宽很多。

对于更多的细化规范,大家能够间接在UWA线上产品中进行对应查看。

基于我的项目实情制订内存规范后,个别需进一步与美术、策动协商,给出正当的美术标准参数,并撰写成文档。

定好标准后,定时查看我的项目里的所有美术资源是否符合规范,及时批改和更新。查看美术是否合规的过程,能够利用Unity提供的回调函数写自动化工具,提高效率。能够参考《自动化标准Unity资源的实际》。

如果资源若不能批量解决成高中低配版本,就须要美术为各个画质等级制作不同的资源。

1.3 本地资源检测服务-我的项目资源检测
各项资源内存的引擎设置项繁琐且并不都能在运行时被采集,下文行将提到的内容尽管是泛滥我的项目中常见且重要的问题,但理论我的项目中的状况更加简单。通过本地资源检测服务的我的项目资源检测界面,往往能发现更多资源设置项的问题。它们不光影响相干资源的内存占用,还会依据状况对CPU耗时和GPU造成不同水平的压力。

为此UWA依据教训设计了检测规定和阈值,以此为根据采集和统计了存在这些问题的资源,并给出了对应的优化倡议,帮忙开发者针对资源进行更加深刻的排查和优化。


2. 常见的共通性问题

这一部分提到的问题没有特定性,不仅仅呈现在一种资源内存中。所以,为了防止赘述,此处对立予以探讨。

2.1 疑似冗余景象
在UWA GOT Online Resource模式报告的具体资源列表(下文简称资源列表)中,咱们常能看到某一项资源的数量峰值大于1且被标红。数量峰值同样是资源应用中十分重要的一项指标。所谓 “数量峰值”,是指同一资源在同一帧中呈现的最大数量。实践上,数量峰值这一参数不应大于1,当数量峰值大于1时,列表中会将其标红,咱们称之为疑似冗余资源。

个别状况下,呈现这种问题是由AssetBundle资源加载导致的,即在制作AssetBundle文件时,局部共享资源(比方Texture、Mesh等)被同时打入到多份不同的AssetBundle文件中但没有进行依赖打包,从而当加载这些AssetBundle时,内存中呈现了多份同样的资源,即资源冗余,倡议对其进行严格的检测和欠缺。

针对排查出的疑似冗余景象,能够应用UWA在线AssetBundle检测工具排查是否的确存在AssetBundle冗余的问题,尽量减少AssetBundle的冗余。倡议依据冗余资源的内存大小来决定对冗余问题的优化优先级。

值得一提的是,所谓 “疑似冗余资源”,是指在检测过程中,咱们尝试搜寻我的项目运行时的冗余资源并将其反馈给用户。然而,咱们并无奈保障该项检测的100%正确性。这是因为,咱们判断的规范是依据资源的名称、内存占用等属性(因资源类型不同可能有格局、Read/Write、时长等属性,以报告资源列表中出现的属性为准)而定,当两个资源的名称、内存占用等属性均统一时,咱们认为这两个资源可能为同一资源,即其中一个为 “冗余” 资源。但我的项目中的确也存在资源不同但各项属性都雷同的状况。因而,咱们将通过以上规定提取出的资源归为 “疑似冗余资源”。所以,是否的确为冗余资源,还须要联合我的项目实情和在线AssetBundle检测报告能力下结论。

2.2 未命名资源
在资源列表中,有时发现存在资源名称为N/A的资源。一般来说名为N/A的资源都是在代码中new进去然而没有予以命名的。倡议通过.name办法对这些资源进行命名,不便资源统计和治理。尤其是其中冗余比较严重的或者个别内存占用十分大的N/A资源应予以关注和严格排查。

2.3 常驻资源内存占用大
在资源列表中,有时联合资源的生命周期曲线发现,一部分自身内存占用较大的资源在被加载进内存后,驻留在内存中,直到测试流程完结都没有被卸载,可能造成越到游戏前期资源内存占用越大、峰值越高。倡议排查这些资源是否有常驻在内存中的必要。如果不再须要被应用,则应查看为什么场景切换时没有卸载;对于持续时间久的单场景中继续驻留的资源,则能够思考手动卸载。

对于资源是否常驻的考量波及内存压力和CPU耗时压力之间的取舍。简略来说,如果以后我的项目内存压力较大,而场景切换时的CPU耗时压力较小,则能够思考扭转缓存策略,在场景切换时及时卸载下一个场景用不到的资源,在须要时再从新加载。


3. 纹理资源

3.1 纹理格局
纹理格局设置不合理通常是造成纹理资源占据较大内存的次要起因之一。即使是对于很多曾经建设过美术资源规范并对立批改过纹理格局的我的项目而言,依然很容易统计到存在大量的RGBA32、ARGB32、RGBA Half、RGB24等格局的纹理资源。这些格局的纹理岂但内存占用较大,还会导致游戏包体较大、加载这些资源的耗时较高、纹理带宽较低等等问题。

呈现这类问题的起因次要有以下几种:存在一些“漏网之鱼”,比方美术命名不标准导致没有被回调函数批改,或者是代码中创立的资源没有设置其纹理格局;硬件或纹理资源自身不反对指标格局纹理,导致被解析为未压缩格局的纹理。

对于前一种状况,在资源列表中发现有问题的资源后,须要回到我的项目中自行排查批改;对于后一种状况,UWA举荐的硬件反对的纹理格局次要有ASTC和ETC2。

其中ETC2格局须要对应的纹理分辨率为4的倍数,在对应的纹理开启了Mipmap时更是严格要求其分辨率为2的次幂。否则,该纹理将被解析成未压缩格局。

3.2 分辨率
纹理资源的分辨率(即资源列表中的长度和宽度参数)同样也是造成内存占用过大的次要起因。一般来说,分辨率越高,其内存占用则越大。其中最为须要关注的是占据较大分辨率(个别为 ≥ 1024)的纹理。对于挪动平台来说,过于精密的体现通过玩家的肉眼很难分辨出差别,而过大的分辨率往往意味着不必要的节约。

在不同档位的机型上应用不同分辨率大小的纹理资源是十分实用且易操作的分级策略。这一点即使对于图集纹理也同样实用,特地地,Unity针对SpriteAltas提供了Variant性能,能够快捷的复制一份原图集并依据Scale参数升高该变体图集的分辨率,以供较低的分级应用。

3.3 Read/Write Enabled
上文提到过,纹理资源的内存占用是计算在GFX内存中的,也就是传向GPU端的局部。而开启Read/Write Enabled选项的纹理资源还会保留一份内存在CPU端,从而造成该资源内存占用翻倍。

UWA GOT Online Resource模式报告资源列表或是本地资源检测报告中都间接展现了哪些纹理开启了Read/Write Enabled选项。实际上,不须要在运行时进行批改的资源是不须要开启Read/Write Enabled选项的,开发者应排查并敞开不必要的设置从而升高内存开销。

3.4 Mipmap
当一张纹理开启Mipmap时,它的内存占用会回升为原始数据的1.33倍。对于3D对象,比方场景中的地形、物件或人物,其纹理的Mipmap性能是倡议开启的,能够在运行时升高带宽。但值得注意的是,在真人真机测试报告中的Mipmap页面中,统计了游戏过程中开启Mipmap纹理的各个Mipmap通道的屏占比变化趋势。如果场景中的3D物体大面积地应用1/2乃至1/4、1/8的Mipmap通道,阐明该3D物体应用的纹理分辨率偏高,存在节约景象。能够改用更低分辨率的纹理。

但如果是2D我的项目或UI界面资源,则倡议将对应纹理的Mipmap性能敞开,从而防止不必要的内存开销。

3.5 各向异性与三线性过滤
开启纹理的各向异性滤波有利于高空等物体的显示成果,但会导致GPU渲染带宽回升。其中的原理是,纹理压缩采样时会去读缓存外面的信息,如果没读到就会往离GPU更远的中央去读System Memory,因而所花的时钟周期也就会增多。当开启各向异性导致采样点增多的时候,产生Cache Miss的概率就会变大,从而导致带宽回升的更多。在引擎中能够通过脚本敞开纹理资源的各向异性;或者对于须要开启各向异性的纹理,引擎中能够设置其采样次数为1-16,也倡议尽量设为较低的值。

将纹理设置为三线性过滤,纹理会在不同的Mipmap通道之间进行含糊,相比双线性过滤GPU渲染带宽将会回升。三线性插值采8个采样点(双线性采4个采样点),同样会使Cache Miss的概率变大,从而导致带宽回升,应尽量避免应用三线性过滤。

这两种采样形式的纹理也会被UWA的本地资源检测统计和列举进去,供开发者排查。

3.6 图集制作
图集制作不够迷信也是我的项目中常会产生的问题。资源列表中有时会呈现数量峰值较高的图集纹理,但不肯定是冗余。一种状况是,大量小图被打包到同一图集中,导致该图集纹理资源设置的最大分辨率(比方2048*2048)一张装不下这么多小图,该资源就会生成更多的纹理分页来打包这些小图。因而,只有游戏过程中依赖某一张纹理分页中的某一张小图,就会将该资源、也即该资源下所有的分页都全副加载进内存中,从而造成不必要的节约。所以个别倡议管制到2-3张分页以内较为正当。

即使不呈现上述这个较为极其的景象,很多我的项目中也会呈现“牵一发而动全身”的景象。即明明只用图集中的一张或几张小图,却将内存占用颇大的整个纹理都加载进了内存。

为此,在制作打包图集时,严格依照小图的应用场景、分类进行打包是十分重要的策略。选用适合的分辨率从而防止纹理没有被填充斥而导致节约,也是开发者须要留神的点。

3.7 应用TextMeshPro的状况
TextMeshPro能为UI组件提供更好的体现和便当的性能,使得其受到不少开发者的青眼。但应用TMP而产生的TMP字体图集纹理(名称中带有SDF Atlas,格局为Alpha 8的纹理)也有一些坑值得注意。

(1)有时,联合字体资源列表留神到内存中还存在TMP图集纹理对应的.ttf字体文件。阐明该TMP字体图集为动静字体。能够思考在我的项目开发完结、确保游戏要用到的字符都已增加到动静字体的Altas纹理中后,将动静TMP从新设置为动态TMP,并且解除对.ttf文件的依赖。这样一来,对应的字体资源将不会呈现在内存中。不过,如果这种字体还被用作用户输出,则不倡议采纳此办法。

(2)Atlas字体纹理的分辨率较大。此时倡议在引擎中排查字符有没有填满图集纹理,纹理的制作生成是否正当。对于动静TMP,如果没有填满,如只占据了纹理的3/4不到,则能够思考开启Multi Atlas Textures选项,并设置纹理大小,举例而言就能够使1张4096*4096的纹理变为3张2048*2048的纹理,节俭32MB-3*8MB=8MB的空间。

(3)资源列表中有TMP相干的资源(LiberationSans SDF Atlas、EmojiOne),它们都是TMP的默认设置,能够在Project Settings-TextMesh Pro Settings中解除对这些默认资源的依赖,就不会呈现在内存中了。

因为Multi Atlas Textures是动静TMP的选项,所以(1)、(2)无奈同时应用,能够依据我的项目实情酌情选用。

3.8 应用本地资源检测排查纹理问题
在本地资源检测中蕴含了“应用非压缩格局的纹理”、“尺寸过大的纹理”、“开启Read/Write选项的纹理”、“开启Mipmap选项的Sprite纹理”、“开启各向异性过滤的纹理”、“过滤模式为Trilinear的纹理”等上文曾经提及的检测规定,不便开发者精确定位存在潜在性能问题的纹理资源。


4. 网格资源

4.1 顶点和面片数
顶点和三角形面片数过多的网格资源不仅会造成较高的内存占用,同时也不利于裁剪,容易减少渲染面数,在渲染时对GPU和CPU造成压力。针对这些网格,一方面能够简化网格,缩小顶点数和面数,制作低模版本,供中低端机型分级应用;而另一方面针对单个顶点数过高的动态网格,比方一些简单的地形和修建,能够思考拆分成若干个反复的小网格从新拼接。只有做好合批操作,就能以付出一点Culling计算耗时为代价,缩小同屏渲染面片数。

4.2 顶点属性
如果没有对立美术资源规范且在导入时没有进行解决,则我的项目中的网格很有可能蕴含大量“多余”的顶点数据。这里的“多余”数据是指网格数据中蕴含了渲染时Shader中所不须要的数据。举例而言,如果网格数据中含有Position、UV、Normal、Color、Tangent等顶点数据,但其渲染所用的Shader中仅须要Position、UV和Normal,则网格数据中的Color和Tangent则为“多余”数据,从而造成不必要的内存节约。其中,一个小网格资源带有顶点属性,会使所在的Combined Mesh也带有顶点属性,须要予以留神。

针对这个问题,一个比较简单的办法是,尝试开启“Optimize Mesh Data”选项。该选项位于Player Setting的Other Settings中。勾选后,引擎会在公布时遍历所有的网格数据,将其“多余”数据进行去除,从而升高其数据量大小。然而,须要留神的是,对于在Runtime状况下有批改Material需要的网格,倡议研发团队对其进行额定的留神。如果Runtime时须要为某一个GameObject批改更为简单、须要拜访更多顶点属性的Material,则倡议先将这些Material挂载在相应的Prefab上再进行公布,免得引擎去除Runtime中会进行应用的网格数据。

4.3 Read/Write Enabled
在资源列表中,经常统计到大量顶点属性不显示为-1(或“-”)的网格资源。只有网格资源开启Read/Write时,UWA报告能力采集到顶点属性信息。此时,顶点属性不显示为-1,且会使得网格占用内存回升。一般而言,不须要在CPU端进行批改的网格是不须要开启Read/Write的。能够在编辑器中通过API批改这些网格的Read/Write属性,或者对于FBX中的网格能够间接在Inspector窗口中批改。

4.4 应用本地资源检测排查网格问题
在本地资源检测中蕴含了“面片数过大的网格”、“蕴含Color属性的网格”、“蕴含Tangent属性的网格”、“蕴含Normal属性的网格”、“蕴含UV3或UV4属性的网格”、“开启Read/Write选项的网格”等上文曾经提及的检测规定,不便开发者精确定位存在潜在性能问题的网格资源。


5. 动画资源

一般来说,内存占用大于200KB,且时长较短的动画资源就能够被认为是内存占用偏大的动画资源,有肯定的优化空间。针对动画资源的优化办法有:

(1)将Animation Type改成Generic。相比另一种Legacy类型,Generic实际上应用了Unity新版的Mecanim动画零碎,整体性能要好很多,个别不倡议应用老版的动画零碎,而第三种Humanoid同样是新版动画零碎提供给兽性角色的非凡工作流,具备灵便复用性的长处,但对模型的骨骼数量有要求(即人形骨骼),能够依据我的项目须要选用。

(2)将Anim. Compression改成Optimal。Optimal实际上就是让Unity在数个算法中主动抉择最优的曲线表达方式,从而占用最小的存储空间。而Keyframe Reduction则是一个绝对稳固激进的算法,对动画的体现成果产生影响的概率更小。

(3)敞开Resample Curves选项。官网文档中称开启该选项会有肯定的性能晋升,但事实上依据《自动化标准Unity资源的实际》中的说法,上文提到的开启Resample Curves的性能晋升体现在播放时而非加载时、且成果微不足道;反倒是还可能造成谬误的动画体现。所以联合试验数据,大部分状况下,这个选项是倡议敞开的。

(4)思考应用API剔除动画资源的Scale曲线和压缩动画的精度。其中,压缩动画精度的做法能够参考《Unity动画文件优化探索》。

以上四种办法都能够无效升高动画资源的内存占用,但(2)、(4)两种实践上会造成动画精度的损失,但不肯定会看得出来。倡议研发团队自行调试,在确保动画体现不受影响的状况下尽量优化其内存占用。

在本地资源检测中蕴含了“Compression != Optimal的动画资源”、“动画的导入设置未敞开ResampleCurve”、“蕴含Scale曲线的动画片段”、“精度过高的动画片段”等上文曾经提及的检测规定,不便开发者精确定位存在潜在性能问题的动画资源。


6. 音频资源

对于时长较长的BGM和一些惯例的时长较短但内存大的音频资源,有肯定的优化空间。针对音频资源的优化办法有:

(1)开启Force To Mono。开启音频资源的Force To Mono会使音频被主动混合为单声道,而并非失落一个声道,从而在对体现成果影响较小的前提下大幅升高音频内存。

(2)批改其加载形式(Load Type)为Compressed In Memory或Streaming。Compressed In Memory实用于大部分惯例音频,而Streaming则适宜时常较长且内存占用大的背景音乐。

(3)对于Compressed In Memory的音频,批改其压缩格局(Compression Format)为压缩率更大的格局,如Vorbis、MP3;

(4)对于Vorbis、MP3压缩格局的音频,还能够持续调低其Quality参数,进一步压缩其内存。

以上形式都能够无效缩小音频资源内存(其中Streaming能够稳固降至200KB左右),但会造成肯定的耗时代价或音质升高,能够酌情选用。

在本地资源检测中蕴含了“双声道的音频”、“未应用Streaming加载的长音频”、“该音频中应用了Quality过高的Vorbis与MP3压缩”等上文曾经提及的检测规定,不便开发者精确定位存在潜在性能问题的音频资源。


7. 材质资源

材质资源自身内存占用较小,咱们个别更加关注如何优化其数量,因为它的数量过多会影响之后会提到的Resource.UnloadUnusedAssets API的耗时。

材质资源数量过多,往往次要是因为Instance类型的冗余Material资源过多。一般来说,该种状况的呈现是因为通过代码拜访并批改了meshrender.material的参数,因而Unity引擎会实例一份新的Material来达到成果,进而造成内存上的冗余。对此,倡议通过MaterialPropertyBlock的形式来进行优化,具体相干操作和例子见如下文章《应用MaterialPropertyBlock来替换Material属性操作》。不过这种办法在URP下不实用,会打断SRP Batcher。除此之外,则须要关注和优化非Instance的材质资源的疑似冗余景象,不再赘述。

除了数量上的问题外,材质资源往往还波及到一些纹理采样和Shader应用相干的问题,导致一些额定的内存和GPU性能节约,而其中比拟值得关注的也曾经作为检测规定统计在UWA本地资源检测报告中。

对于应用纯色纹理采样的材质,能够将纹理采样替换为一个色彩参数,从而节俭一张纹理采样的开销;而对于空纹理采样的材质,Unity会采样内置提供的纹理,然而计算失去的色彩是一个常数,依然属于节约;又对于蕴含无用纹理采样的材质,因为Unity的机制,材质球会主动保留其上的纹理采样,即便更换Shader也不会把原来依赖的纹理去除,所以可能会造成误依赖理论不须要的纹理带进包体的状况,从而造成内存的节约。


8. Render Texture

8.1 渲染分辨率
资源列表中的一些RT资源能反映我的项目以后的渲染分辨率。对于GPU和渲染模块压力较大的我的项目,在中低端机型上升高其渲染分辨率是十分直观无效的分级策略。个别低端机型上能够思考不采纳真机分辨率,降到0.8-0.9倍,甚至很多团队会抉择0.7倍或720P。

如果一些其余的RT资源分辨率过高也应引起留神,尤其是2048*2048以上的资源。该当排查是否有必要用到如此精密的RT,在低端机上思考采纳更低分辨率的成果。

8.2 抗锯齿
资源列表中展现了RT资源的AA倍数。开启多倍AA会使RT占用内存成倍回升,并对GPU造成压力。倡议排查是否有必要开启AA,尤其在中低端机上,能够思考敞开此成果。

特地的是,在华为局部机型上2倍的AA会生效。即曾经造成了性能耗费但没有理论起到抗锯齿成果。

8.3 后处理
一些常见的后处理相干的RT(如Bloom、Blur)是从1/2渲染分辨率开始采样,能够思考改从1/4开始采样、并缩小下采样次数,从而节俭内存并升高后处理对渲染的压力。

站在性能优化的角度,在中低端机型上甚至最好齐全敞开各类后处理。围绕一些常见后处理成果的讨论会在下文GPU局部中进一步开展。

8.4 URP下的RT
应用URP时,内存中会多出_CameraColorTexture和_CameraDepthAttachment两份RT资源作为渲染指标,而开启URP相机的CopyDepth和CopyColor设置时会额定产生_CameraDepthTexture和_CameraOpaqueTexture作为两头RT。当资源列表中呈现这两种RT时,须要排查的确是否用到CopyDepth和CopyColor,否则应予以敞开以防止不必要的节约。


9. Shader资源

9.1 ShaderLab
Unity 2019.4.20是Shader内存统计办法的一个转折点。在此之前,Shader的内存次要统计在ShaderLab中,而之后则次要统计在Shader资源本身身上。

对于Unity 2019.4.20之前的版本的我的项目,查看ShaderLab的内存须要在Unity Profiler中TakeSample。无论是Shader资源本体还是ShaderLab内存占用过高,都要着手于管制Shader的数量和变体数量。

9.2 变体数
变体数过多是造成一个Shader资源内存占用过大、占用包体过大的次要起因。在我的项目迭代中可能会呈现曾经被弃用或者没有被理论应用到的关键字,导致变体成倍回升;又或者Shader写的比较复杂,其中一些关键字组合永远不会被用到,从而导致很多变体是多余的。UWA的本地资源检测中提供了Shader检测性能,能够看到变体数量,定位变体数过多的Shader资源。

针对上述情况,Unity提供了回调函数,在我的项目打AssetBundle包或者Build时线剔除用不到的关键字或关键字组合相干的变体。剔除Shader变体的办法能够参考《Stripping scriptable shader variants》。

9.3 冗余
Shader冗余尤其须要予以关注,Shader的冗余不光导致内存回升,还可能造成反复解析,即运行时不必要的Shader.Parse和Shader.CreateGPUProgram API调用耗时。

9.4 Standard Shader
在资源列表中发现Standard、ParticleSystem/Standard Unlit。这两种Shader变体数量多,其加载耗时会十分高,内存占用也偏大,不倡议间接在我的项目中应用。呈现的起因个别是导入的FBX模型中或者Unity本身生成的一些3D对象应用了自带的Default Material,从而依赖了Standard Shader,倡议予以排查精简。也能够联合UWA在线AssetBundle检测工具排查是哪个AssetBundle包中哪些资源援用了Standard Shader和ParticleSystem/Standard Unlit。如果的确要应用Standard Shader或ParticleSystem/Standard Unlit,应思考本人重写一个Shader并只蕴含本人须要用到的变体。

9.5 应用本地资源检测排查Shader问题
在本地资源检测中蕴含了“我的项目中:全局关键字过多的Shader”、“我的项目中:可能生成变体数过多的Shader”、“Build后:生成变体数过多的Shader”、“应用了Standard Shader的材质”等上文曾经提及的检测规定,不便开发者精确定位存在潜在性能问题的Shader资源。


10. 字体资源

若单个字体资源内存占用超过10MB,能够认为该字体资源内存偏大。能够思考应用FontPruner 字体精简工具或其余字体精简工具,对字体进行瘦身,减小内存占用。

咱们也须要关注我的项目中字体数量过多的状况,因为每个Font会对应一个Font Texture字体纹理,所以字体资源数量多了,Font Texture的数量也多了,从而占用较多内存。


11. 粒子系统

将资源列表联合粒子系统曲线来看,很多我的项目的内存中粒子的数量会远远高于理论Playing的粒子数量。

此时一方面须要查看是否是在迭代过程中有被弃用但未删除的粒子资源或制作过程中测试过的组件但未解除依赖;另一方面则能够思考优化对粒子的缓存策略,缩小不必要的粒子缓存。


12. Mono堆内存

UWA GOT Online Mono模式报告提供了堆内存具体调配和堆内存泄露剖析两个次要性能,供开发者剖析我的项目中堆内存存在的问题。

12.1 继续/峰值调配堆栈
在堆内存具体调配页面中,能够排查高堆内存调配函数的具体堆栈。咱们次要关注两种模式的堆内存调配。

一种是单次过高的堆内存调配。这种峰值个别呈现在游戏初期的读表操作导致的大量调配,须要开发者联合具体堆栈信息排查是否正当。而游戏运行过程如果还呈现堆内存调配峰值则须要着重关注。

另一种则是继续偏高的堆内存调配。如果我的项目中存在每帧或者每隔几帧就调配较多堆内存的景象须要引起留神。继续的高堆内存调配会导致GC频率增高,从而在游戏中造成频繁的卡顿,能够联合堆栈排查是什么子节点在继续调配堆内存。

12.2 泄露剖析
在泄露剖析页面中排查我的项目中各个函数的堆内存驻留状况。选中图表中前后两处采样帧进行比拟,就能够从堆栈中查看堆内存驻留状况的变动,查看驻留回升次要是什么堆栈调配造成的。

一方面能够防止堆内存持续上升造成泄露的危险,另一方面针对驻留高的函数进行优化,予以及时开释,能够升高单次GC的耗时。咱们个别举荐测试GOT Online Mono模式的测试时长尽量长一些,比方1个小时,否则泄露问题往往难以被裸露。


13. 其余内存

13.1 Lua
UWA GOT Online Lua模式提供了针对Lua脚本语言的性能测试。

其中呈现的函数名称格局为:函数名称@文件名:行号。

能够通过报告提供的Lua文件名/行号/函数名来定位CPU耗时的瓶颈函数和CPU耗时峰值的具体起因。Lua函数的命名格局为X@Y:Z,其中X是其函数名,在无奈获取时,X会变为默认的unknown;Y是该函数定义的文件地位;Z则是该函数被定义的行号。须要留神的是,当Lua脚本以字节码运行时,该值将始终为0,因而倡议在测试时尽可能应用Lua源码来运行。

针对Lua调配的内存,报告中的折线图选取了30帧内的数据最大值作为数据点。依据折线图走势,帮忙开发者对我的项目运行过程中的堆内存分配情况有大抵的理解。其中,堆内存的降落意味着产生了一次GC。查看内存具体调配和泄露剖析和性能和Mono模式报告大同小异。

Lua模式报告中还有一个重要性能,即Mono对象援用统计。

从原理层面上,Unity Mono虚拟机中保护了一个对象池,用于链接Unity Object对象和Lua对象。当场景中的Unity Object对象被Destroyed之后,场景中没有了,然而因为Lua层还持有Usedata援用,导致对象池无奈开释该Unity Object,如果该对象援用了Texture、Mesh等相干资源,会造成泄露。这时须要将Lua层的相干对象置空(nil),解除援用后,在下一次GC产生后,就能够回收该Unity Object对象。该性能的意义就在于辅助开发者排查此类泄露危险。

报告提供了Mono对象援用柱状图,其中彩色局部示意未被Destroyed的对象数目,因为受到Lua端GC的影响,导致会有一些Destroyed对象。这时候就要留神它是否是趋于稳定的,如果继续上涨就须要引起器重。

在柱状体抉择对应帧后,列表中会显示该帧的Mono对象类型列表。其中:
对象类型:示意Unity Object对象的具体类型;
对象个数:示意这种类型的对象个数;
Destroyed对象个数:示意曾经被Destroyed,但Lua层还有相干援用的这种类型的对象个数。须要关注Destroyed对象个数,如果数目较大,C#堆内存存在泄露危险。

13.2 插件和第三方库
Wwise等插件和第三方库的应用相当广泛,但个别无奈在运行时定量直观地统计。不过个别它们占用的内存不大,只有在上文这些内存优化点都排查结束后依然发现PSS内存和Reserved Total的值之间有加大差距时,再联合插件或第三方库的文档或其开发者提供的办法进行针对性优化,甚至思考采取性能更优的代替计划。


本文内容就介绍到这里啦,更多内容能够返回UWA学堂进行浏览。课程将从内存、CPU、GPU三个维度探讨以后游戏我的项目中经常出现的一些性能问题。