怎么让unitygpu视图的摄像机和game视图保持一致

项目的性能优化主要围绕CPU、GPU和内存三大方面进行接上期专讲,我们本期和大家分享内存方面的优化心得

无论是游戏还是VR应用,内存管理都是其研发阶段的重中之重

嘫而,在我们测评过的大量项目中90%以上的项目都存在不同程度的内存使用问题。就目前基于unitygpu视图引擎开发的移动游戏和移动VR游戏而言內存的开销无外乎以下三大部分:1.资源内存占用;2.引擎模块自身内存占用;3.托管堆内存占用。

如果您的项目存在内存问题一定逃不出以仩三种情况。今天我们就这三种情况逐一进行解释。

在一个较为复杂的大中型项目中资源的内存占用往往占据了总体内存的70%以上。因此资源使用是否恰当直接决定了项目的内存占用情况。一般来说一款游戏项目的资源主要可分为如下几种:纹理(Texture)、网格(Mesh)、动畫片段(AnimationClip)、音频片段(AudioClip)、材质(Material)、着色器(Shader)、字体资源(Font)以及文本资源(Text Asset)等等。其中纹理、网格、动画片段和音频片段则昰最容易造成较大内存开销的资源。

纹理资源可以说是几乎所有游戏项目中占据最大内存开销的资源一个6万面片的场景,网格资源最大財不过10MB但一个的纹理,可能直接就达到16MB因此,项目中纹理资源的使用是否得当会极大地影响项目的内存占用
那么,纹理资源在使用時应该注意哪些地方呢

纹理格式是研发团队最需要关注的纹理属性。因为它不仅影响着纹理的内存占用同时还决定了纹理的加载效率。一般来说我们建议开发团队尽可能根据硬件的种类选择硬件支持的纹理格式,比如Android平台的ETC、iOS平台的PVRTC、Windows PC上的DXT等等因此,我们在UWA测评报告中将纹理格式进行详细罗列,以便开发团队进行快速查找一步定位。

在使用硬件支持的纹理格式时你可能会遇到以下几个问题:

    甴于ETC、PVRTC等格式均为有损压缩,因此当纹理色差范围跨度较大时,均不可避免地造成不同程度的“阶梯”状的色阶问题因此,很多研发團队使用RGBA32/ARGB32格式来实现更好的效果但是,这种做法将造成很大的内存占用比如,同样一张的纹理如果不开启Mipmap,并且为PVRTC格式则其内存占用为512KB,而如果转换为RGBA32位则很可能占用达到4MB。所以研发团队在使用RGBA32或ARGB32格式的纹理时,一定要慎重考虑更为明智的选择是尽量减少纹悝的色差范围,使其尽可能使用硬件支持的压缩格式进行储存2.0的设备,其纹理格式仅能支持ETC1格式该格式有个较为严重的问题,即不支歭Alpha透明通道使得透明贴图无法直接通过ETC1格式来进行储存。对此我们建议研发团队将透明贴图尽可能分拆成两张,即一张RGB24位纹理记录原始纹理的颜色部分和一张Alpha8纹理记录原始纹理的透明通道部分然后,将这两张贴图分别转化为ETC1格式的纹理并通过特定的Shader来进行渲染,从洏来达到支持透明贴图的效果该种方法不仅可以极大程度上逼近RGBA透明贴图的渲染效果,同时还可以降低纹理的内存占用是我们非常推薦的使用方式。

当然目前已经有越来越多的设备支持了OpenGL ES 3.0,这样Android平台上你可以进一步使用ETC2甚至ASTC这些纹理格式均为支持透明通道且压缩比哽为理想的纹理格式。如果你的游戏适合人群为中高端设备用户那么不妨直接使用这两种格式来作为纹理的主要存储格式。

一般来说紋理尺寸越大,则内存占用越大所以,尽可能降低纹理尺寸如果512x512的纹理对于显示效果已经够用,那么就不要使用的纹理因为后者的內存占用是前者的四倍。因此我们在UWA测评报告中,将纹理的尺寸进行详细展示以便开发团队进行快速检测。

Mipmap旨在有效降低渲染带宽的壓力提升游戏的渲染效率。但是开启Mipmap会将纹理内存提升1.33倍。对于具有较大纵深感的3D游戏来说3D场景模型和角色我们一般是建议开启Mipmap功能的,但是在我们的测评项目中经常会发现部分UI纹理也开启了Mipmap功能。这其实就没有必要的绝大多数UI均是渲染在屏幕最上层,开启Mipmap并不會提升渲染效率反倒会增加无谓的内存占用。因此建议研发团队在UWA的测评报告中通过Mipmap一项进行排序,详细检测开启Mipmap功能的资源是否为UI資源

一般情况下,纹理资源的“Read & Write”功能在unitygpu视图引擎中是默认关闭的但是,我们仍然在项目深度优化时发现了不少项目的纹理资源会开啟该选项对此,我们建议研发团队密切关注纹理资源中该选项的使用因为开启该选项将会使纹理内存增大一倍。


网格资源在较为复杂嘚游戏中往往占据较高的内存。对于网格资源来说它在使用时应该注意哪些方面呢?

在我们深度优化过的大量项目中Mesh资源的数据中經常会含有大量的Color数据、Normal数据和Tangent数据。这些数据的存在将大幅度增加Mesh资源的文件体积和内存占用其中,Color数据和Normal数据主要为3DMax、Maya等建模软件導出时设置所生成而Tangent一般为导入引擎时生成。

更为麻烦的是如果项目对Mesh进行Draw Call Batching操作的话,那么将很有可能进一步增大总体内存的占用仳如,100个Mesh进行拼合其中99个Mesh均没有Color、Tangent等属性,剩下一个则包含有Color、Normal和Tangent属性那么Mesh拼合后,CombinedMesh中将为每个Mesh来添加上此三个顶点属性进而造成佷大的内存开销。正因如此我们在UWA测评报告中为每个Mesh展示了其Normal、Color和Tangent属性的具体使用情况,研发团队可以直接针对每种属性进行排序查看直接定位出现冗余数据的资源。

一般来说这些数据主要为Shader所用来生成较为酷炫的效果。所以建议研发团队针对项目中的网格资源进荇详细检测,查看该模型的渲染Shader中是否需要这些数据进行渲染

限于篇幅,我们今天只针对纹理和网格资源进行详细介绍对于动画片段、音频片段等其他资源,建议您直接通过UWA测评报告中进行查看同时,我们会在后续的资源专题中进行详细讲解敬请期待。

一般情况下上面所指出的引擎各组成部分的内存开销均比较小,真正占据较大内存开销的是这两处:WebStream 和 SerializedFile其绝大部分的内存分配则是由AssetBundle加载资源所致。简单言之当您使用new WWW加载多个AssetBundle文件,且AssetBundle又无法及时释放时WebStream的内存可能会很大,这是研发团队需要时刻关注的

  • 是否存在AssetBundle没有被清理幹净的情况。开发团队可以通过unitygpu视图 Profiler直接查看其使用具体的使用情况并确定Take Sample时AssetBundle的存在是否合理;

注意:关于AssetBundle的详细管理机制,建议查看峩们之前的

对于目前绝大多数基于unitygpu视图引擎开发的项目而言,其托管堆内存是由Mono分配和管理的“托管” 的本意是Mono可以自动地改变堆的夶小来适应你所需要的内存,并且适时地调用垃圾回收(Garbage Collection)操作来释放已经不需要的内存从而降低开发人员在代码内存管理方面的门槛。

但是这并不意味着研发团队可以在代码中肆无忌惮地开辟托管堆内存因为目前unitygpu视图所使用的Mono版本存在一个很严重的问题,即:Mono的堆内存一旦分配就不会返还给系统。这意味着Mono的堆内存是只升不降的举个例子,项目运行时在场景A中开辟了60MB的托管堆内存,而到下一场景B时只需要使用20MB的托管堆内存,那么Mono中将会存在40MB空闲的堆内存且不会返还给系统。这是我们非常不愿意看到的现象因为对于游戏(特别是移动游戏)来说,内存的占用可谓是寸土寸金的让Mono毫无必要地锁住大量的内存,是一件非常浪费的事情所以,我们在UWA测评报告Φ为研发团队统计了测试过程中累积的函数堆内存分配量,大家只需要通过查看堆内存分配Top10的函数即可快速对其底层代码实现进行查看,定位是否有分配不必要堆内存的代码存在

读到这里,你可能会产生这样的疑问:我知道了哪些函数的堆内存分配大了但是我该如哬去进一步定位不必要的堆内存呢?

这是我们经常遇到的问题所以在我们的深度项目优化服务中,我们都会直接进驻到项目团队现场查看项目代码并对问题代码进行定位。在经过了大量的深度检测后我们发现用户不必要的堆内存分配主要来自于以下几个方面:

    Class/Container/Array等。研發团队切记不要在Update、FixUpdate或较高调用频率的函数中开辟堆内存这会对你的项目内存和性能均造成非常大的伤害。做个简单的计算假设你的項目中某一函数每一帧只分配100B的堆内存,帧率是1秒30帧那么1秒钟游戏的堆内存分配则是3KB,1分钟的堆内存分配就是180KB10分钟后就已经分配了1.8MB。洳果你有10个这样的函数那么10分钟后,堆内存的分配就是18MB这期间,它可能会造成Mono的堆内存峰值升高同时又可能引起了多次GC的调用。在峩们的测评项目中一个函数在10分钟内分配上百MB的情况比比皆是,有时候甚至会分配上GB的堆内存
  • Log输出。我们发现在大量的项目中仍然存在大量Log输出的情况。建议研发团队对自身Log的输出进行严格的控制仅保留关键Log,以避免不必要的堆内存分配对此,我们在UWA测评报告中對Log的输出进行了详细的检测不仅提供详细的性能开销,同时占用Log输出的调用路径这样,研发团队可直接通过报告定位和控制Log的输出
  • UIPanel.LateUpdate。这是NGUI中CPU和堆内存开销最大的函数它本身只是一个函数,但NGUI的大量使用使它逐渐成为了一个不可忽视规则该函数的堆内存分配和自身CPU開销,其根源上是一致的即是由UI网格的重建造成。因此其对应的优化方法是直接查看中的UI模块讲解。

关于代码堆内存分配的注意点还囿很多比如String连接、部分引擎API(GetComponent)的使用等等,这些已经是老生常谈了鉴于篇幅限制不在此处多作介绍,大家感兴趣可以Google自行搜索后續也会有专门的代码效率专题讲解,敬请关注

在大家使用过UWA之后,对于UWA推荐的内存标准值提出了很大的疑惑在这里,我们也分享下UWA内存标准的制定规则

(1)150MB的总体内存标准主要由以下两个因素得出:

  • 经过了大量的项目优化后总结而得。其实对于目前市场主流的unitygpu视图遊戏来说,其内存占用主要集中在120~200MB同时,顾及到iPhone4和512MB/768MB等低端Android机型其应用的自身总体内存占用不可超过200MB(iPhone4的安全线应该在180MB左右),所以我們将Reserved Total设定在150MB这是unitygpu视图引擎的自身内存分配,以保证App在使用到的系统库后其OS中的整体内存也在200MB以下。
  • 某些渠道对Android游戏的PSS内存进行了严格嘚限制一般要求游戏的PSS内存在200MB以下。这是我们将Reserved Total内存设定在150MB的另外一个重要原因

(2)当总体内存设定为150MB后,我们进一步对其具体分配進行了设定但需要说明的是,这里的内存分配其实并没有严格的公式来进行论证仅是我们在大量的项目优化工作中提炼出的经验值。目前项目较为合理的内存分配如下:

需要指出的是,150MB中并没有涵盖较为复杂的字体文件(比如微软雅黑)以及Text Asset这些需要根据游戏需求洏定。

(3)目前的UWA内存标准是较为苛刻的对于中高端设备而言,其内容允许量其实要比150MB要大得多但我们坚持认为,在研发过程中一個严苛的标准对于一个项目来说是一件好事。至少它可以为大家提个醒,让大家时刻关注自己的问题据我们了解,目前的三到五线城市其低端手机的覆盖率还是相当高的。同时对于中高端移动设备,我们仍在不断试验和研究中我们希望在不久的将来可以做到针对各种不同档次的机型都给出一个更为合理的推荐值,从而让大家更为简单地对内存进行管理

以上所说的是游戏项目中主要的内存分配情況,希望读到此处的你可以更加了解unitygpu视图项目的内存开销和潜在问题,并对自己的项目进行更有针对性的检测

内存泄露是开发人员在項目研发过程中最常见也最不愿遇到的问题。就目前来看大家对于判断项目是否存在内存泄露仍然存在一些误区:

    我的项目进出场景前後内存回落不一致,比如进入场景后内存增加40MB,出来后下降30MB仍有10MB内存没有返回给系统,即说明内存存在泄露情况 我的项目在进出场景前后,unitygpu视图 Profiler中内存回落正常但Android的PSS数值并没有完全回落(出场景后的PSS值高于进场景前的PSS值),即说明内存存在泄露情况

以上是我们遇箌的开发团队反馈给我们的典型问题。相信大多数开发团队都会遇到类似的情况在此有必要说明一下,以上两种情况均不能表明内存存茬泄漏问题即便内存在一段时间始终保持增长的趋势,也不能简单地判定其存在内存泄露因为造成内存不能完全回落的情况有很多,仳如资源加载后常驻内存以备后续使用、Mono堆内存的只升不降等等这些均可造成内存无法完全回落。一般来说我们推荐的判断内存是否泄漏的方法如下:

一、检查资源的使用情况,特别是纹理、网格等资源的使用

在我们进行过的项目深度优化过程中资源泄漏是内存泄露嘚主要表现形式,其具体原因是用户对加载后的资源进行了储存(比如放到Container中)但在场景切换时并没有将其Remove或Clear,从而无论是引擎本身还昰手动调用Resources.UnloadUnusedAssets等相关API均无法对其进行卸载进而造成了资源泄露。对于这种情况的排查相当困难这是因为项目中的资源量过于巨大,泄露資源往往很难定位因此,我们在UWA测评报告中对项目中的每个资源都进行了详细的监控并通过“生命周期”这一衡量指标让大家可以清楚地了解到每个资源在项目运行过程中的使用范围。

这样大家可以通过资源的“生命周期”属性来快速查看有哪些资源是“常驻”内存嘚,并且判断该资源是“预加载”资源还是“泄露”资源

同时,项目中所使用的总资源数量往往是成百上千的让大家逐个资源检查过來是一件很费力的事情。所以我们推出了资源的“场景比较”功能。建议大家通过以下两种方式进行资源比较以便更快地找到存在“泄露”问题的资源


  • 同种类型场景或同一场景进行比较

一般来说,同种场景或同一场景的资源使用应该是较为固定的比如游戏项目中的主城场景或主界面场景。通过比较不同时刻同一场景的资源信息可以快速帮你找到其资源使用的差异情况。这样你只需判断这些“差異”资源的存在是否合理,即可快速判定是否存在资源泄露已经具体的泄露资源。

除一些常驻资源外不同类型的场景,其资源使用是唍全不同的比如,游戏中主城和战斗副本的资源除少部分常驻内存的资源外,二者使用的绝大部分资源应该是不一致的所以,通过仳较两种不同类型的场景你可以直接查看比较结果中的“共同资源”,并判断其是否确实为预先设定好的常驻资源如果不是,则它很鈳能是“泄露”资源需要你进一步查看项目的资源管理是否存在漏洞。

AssetBundle的管理不当也会造成一定的内存泄露即上一场景中使用的AssetBundle在场景切换时没有被卸载掉,而被带入到了下一场场景中对于这种情况,建议直接通过Profiler Memory中的Take Sample来对其进行检测通过直接查看WebStream或SerializedFile中的AssetBundle名称,即鈳判断是否存在“泄露”情况


承接上述“误区二”中的说法,“unitygpu视图 Profiler中内存回落正常但Android的PSS数值并没有完全回落”是有可能的,这是因為unitygpu视图 Profiler反馈的是引擎的真实分配的物理内存而PSS中记录的则包括系统的部分缓存。一般情况下Android或iOS并不会及时将所有App卸载数据进行清理,為了保证下次使用时的流畅性OS会将部分数据放入到缓存,待自身内存不足时OS Kernel会启动类似LowMemoryKiller的机制来查询缓存甚至杀死一些进程来释放内存。因此并不能通过一两次的PSS内存没有完全回落来说明内存泄露问题。

我们推荐的测试方式是在两个场景之间来回不停切换比如主城囷战斗副本间。理论上来说多次切换同样的场景,如果Profiler中显示的unitygpu视图内存回落正常那么其PSS/Instrument的内存数值波动范围也是趋于稳定的,但如果出现了PSS/Instrument内存持续增长的情况则需要大家注意了。这可能有两种可能:

  • unitygpu视图引擎自身的内存泄露问题这种概率很小,之前仅在少数版夲中出现过

  • 第三方插件在使用时出现了内存泄露。这种概率较大因为Profiler仅能对unitygpu视图自身的内存进行监控,而无法检测到第三方库的内存汾配情况因此,在出现上述内存问题时建议大家先对自身使用的第三方库进行排查。

目前unitygpu视图所使用的Mono版本中存在一个较大的问题,即内存一旦分配则不会再返回给系统。这就衍生出另外一个问题—— 无效的Mono堆内存它是Mono所分配的堆内存,但却没有被真正利用上洇此称之为“无效”。那么如何查看我的项目中是否存在较大量的“无效堆内存”呢

在UWA测评报告中我们提供了内存随项目运行的分配情况,如下图所示其中,蓝线和紫线的分离情况反映了无效堆内存的分配大小。比如图中所选中时刻,蓝线的Reserved Total为当前项目所占据嘚总物理内存而紫线的Used Total为当前项目所使用的总物理内存,这说明当前项目中的空闲内存为57.1MB(200.4-143.3)而这其中主要由两部分组成,空闲的unitygpu视圖引擎内存和无效的Mono堆内存其中,空闲的unitygpu视图内存为17.1MB(92.0-74.9)所以当前所选帧的无效Mono堆内存为40.0MB。并且从图中可以看出,蓝线和紫线在运荇过程中一直分得较开这说明一直存在不小的Mono堆内存处于“无效”状态。这是一件很浪费的事情特别是对于内存寸土寸金的移动设备洏言。

那么我们应该如何避免或减少过多“无效堆内存”的分配呢?我们推荐的做法如下:

  • 避免一次性堆内存的过大分配Mono的堆内存也昰“按需”逐步进行分配的。但如果一次性开辟过大堆内存比如New一个较大Container、加载一个过大配置文件等,则势必会造成Mono的堆内存直接冲高所以研发团队对堆内存的分配需要时刻注意;

  • 避免不必要的堆内存开销。UWA测评报告中将项目运行过程中堆内存分配Top10函数进行罗列限于篇幅,我们不再此处进行一一赘述研发团队可以直接查看之前一篇的相关文章。

在内存管理方面还有一个大家必须关注的话题——资源冗余。在我们测评过的大量项目中95%以上的项目均存在不同程度的资源冗余情况。所谓“资源冗余”是指在某一时刻内存中存在两份甚至多份同样的资源。导致这种情况的出现主要有两种原因:

同一份资源被打入到多份AssetBundle文件中举个例子,同一张纹理被不同的NPC所使用哃时每个NPC被制作成独立的AssetBundle文件,那么在没有针对纹理进行依赖打包的前提下就会出现该张纹理出现在不同的NPC AssetBundle文件中。当这些AssetBundle先后被加载箌内存后内存中即会出现纹理资源冗余的情况。对此我们建议研发团队在发现资源冗余问题后,对相关AssetBundle的制作流程一定要进行检查

哃时,我们在UWA测评中为每个资源引入了一个衡量指标——“数量峰值”它指的是同一资源在同一帧中出现的最大数量。如果大于1则说奣该资源很可能存在 “冗余资源”。大家可以通过这一列进行排序即可立即查看项目中的资源冗余情况。


在unitygpu视图引擎中当我们修改了┅些特定GameObject的资源属性时,引擎会为该GameObject自动实例化一份资源供其使用比如Material、Mesh等。以Material为例我们在研发时经常会有这样的做法:在角色被攻擊时,改变其Material中的属性来得到特定的受击效果这种做法则会导致引擎为特定的GameObject重新实例化一个Material,后缀会加上(instance)字样其本身没有特别夶的问题,但是当有改变Material属性需求的GameObject越来越多时(比如ARPG、MMORPG、MOBA等游戏类型)其内存中的冗余数量则会大量增长。如下图所示随着游戏的進行,实例化的Material资源会增加到333个虽然Material的内存占用不大,但是过多的冗余资源却为Resources.UnloadUnusedAssets API的调用效率增加了相当大的压力

一般情况下,资源属性的改变情况都是固定的并非随机出现。比如假设GameObject受到攻击时,其Material属性改变随攻击类型的不同而有三种不同的参数设置那么,对于這种需求我们建议你直接制作三种不同的Material,在Runtime情况下通过代码直接替换对应GameObject的Material而非改变其Material的属性。这样你会发现,成百上千的instance Material在内存中消失了取而代之的,则是这三个不同的Material资源其中的益处,对于能够阅读到这里的你来说应该已经不需要我多说了。:)

以上则昰我们在内存优化工作中的经验和心得希望它对你的项目研发有所帮助。优化永远没有统一的标准方案只有最适合你项目的方案,希朢大家可以活学活用不要放过任何一处让你感觉“不对劲”的地方。最后提醒大家——“勿以善小而不为勿以恶小而为之”,共勉!


1.游戏运行之前的Scene视图

2.游戏运行之湔的Game视图

 3.游戏运行后的Game视图将poject面板向上拉发现游戏界面变宽了

5.回到Scene面板发现游戏界面发生了变化,这可是真特么的苦恼啊又要从新调游戲界面

 调整GAME视图的分辨率为固定的 底下那个加号也可以自己设置分辨率 

下载13浏览人数928交付方式直接下载

【1】资源来自网络仅限于个人学习研究,请勿用于任何商业用途请支持或购买正版,尊重版权请严格遵守国家相关著作版权保护的法律和规则,请下载24小时内务必删除否则后果自负,本站不承担任何责任及连带责任!【2】本站为学习平台所分享的资源以学习为目嘚,并不能保证所有源码人人都能编译因素太多,旨在学习参考无任何技术支持,如果您要求完美或追求细节请勿下载,大家都不嫆易互相理解,才能让更多好的学习资源出现!


【3】部分素材压缩包因体积过大而上传到百度等网盘上如果发现在本站下载的压缩包呮要有几K大小,说明该压缩包里只是网盘的下载链接并非文件损坏,本站的所有素材都是经过了审核大家可放心下载,欢迎监督反馈
【4】做个好平台真心不容易,我们一直在努力因本站素材量大,难免会出现某网盘下载链接失效等问题请大家及时反馈,我们会及時修正保证您可以拿到素材请大家支持和理解!

免责声明:本网所展示的素材与服务信息由买卖双方自行提供,其真实性、准确性和合法性由信息发布人负责本网不提供任何保证,并不承担任何法律责任如有不妥之处请及时反馈,本网将会妥善处理

友情提醒:本站旨在游戏开发的学习,所分享的素材资源均来源于网络仅适用于学习参考,尊重版权禁止用于任何商业用途,否则后果自负所展示嘚素材版权归原作者或公司所有,如果本站素材侵犯了您的权益请联系我们,我们将及时处理

我要回帖

更多关于 unitygpu视图 的文章

 

随机推荐