1)Instruments如何看Mono内存分配
2)关于Addressable v1.11.2的疑问
3)展开UV2时导致Mesh顶点数增加
4)提升Unity编辑器中代码的编译速度
5)Renderdoc调试的疑问
这是第217篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。
UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)
Memory
Q:例如在分配了一个10MB数组,对应在Unity Profiler中会看到开辟了至少10MB大小的Mono内存。
那么在Instruments中,如何查看分配的内存信息呢?Allocations中的信息是此进程中分配的所有内存信息吗,尝试分配过100MB内存,Allocations中的统计没有任何增长。
A:我这边也做了测试:创建了100MB大小的int数组,Size实际应该是400MB。
然后到Profile观察:
可以看到ManagedHeap正确分配了这400MB的空间。
然后打包iOS后到Xcode运行,运行前首先把Run这个Scheme的Malloc Stack勾上。
RUN以后点选Memory并导出Memory Graph来观察:
由于应用程序的内存都是在VirtualMemory空间分配的,因此查看VM Regions的VM_ALLOCATE部分。
可以发现128X3+16刚好400MB的分配。
调用堆栈也很好确定:
正是我们的测试代码。
然后我们来看Instruments。首先是Allocations部分,有一点要注意,该栏的下部有一些选项:
注意最后一个选项,如果选择第一个:
All Heap & Anonymous VM,All Heap对应App实际分配的物理空间,不包含VM,Anonymous VM的官方解释是:
interesting VM regions such as graphics- and Core Data-related. Hides mapped files, dylibs, and some large reserved VM regions。
因此一些比较大的预留分配空间是不会显示的。
将这个选项切换为All VM Regions,就能看到分配的400M了:
并且右边详情页面也正确显示了调用堆栈:
另外,我们还可以从VM Tracker来观察。打开VMTracker的Snapshots:
就能看到这400MB的详细分配信息:
可以发现,Virutal Size略大于400MB,因为程序其他部分也要申请一些内存。而这400MB又分别保存在Resident和Swapped内,其中Resident部分又基本等于Dirty Size,说明这部分大小的空间被标记了Dirty是不能被交换出去的,剩下240MB左右空间是Clean空间,可以暂时被交换出去以保证有足够的物理空间能使用。这也是因为我们只是申请了这部分空间,并没有进行具体的赋值初始化和使用。
那如果赋值使用了呢?修改代码测试
运行Instruments后再观察:
可以清楚的发现这400MB都在Dirty Size内。这种情况真正会给该App和iOS以内存压力。
推荐阅读:
《写给Unity开发者的iOS内存调试指南》
感谢黄程@UWA问答社区提供了回答
Addressable
Q:关于Addressable v1.11.2开始编辑器在“Fast Mode”模式下运行会获取SubAsset失败的问题。
A:今天将项目使用Addressables系统从1.8.4升级到1.14.2。突然发现AssetReference指向的资源进行实例化总是报Key无效的错误。调查后发现从1.11.2开始,为了给FastMode进一步加速,官方修改了流程。
之前版本即使是Fast Mode下,也是要进行一次Build,并且Play时读取Build出来的Catalog,Catalog会序列化所有的AssetEntry和SubAsset,生成ResourceLocationMap对象然后进行检索。我们使用了不少AssetReference来指向SubAsset使用。这时使用没有问题。
1.11.2版本开始,Fast Mode直接提供编辑器环境下AddressableAssetSettings对象的GUID而非Catalog文件路径,因此Play后初始化时则会启用FastMode专用的初始化操作FastModeInitializationOperation,这时生成的不是ResourceLocationMap,而是AddressableAssetSettingsLocator,这个Locator只是遍历了编辑器Group窗口对应可见的Group内的AssetEntry,而AssetEntry内部的SubAsset则不会被遍历到,因此如果游戏中用到SubAsset,就会报Key无效的错误。
官方Changelog:
Refactored Play Mode Script for "Use Asset Database" to pull data directly from the settings. This reduces the time needed to enter play mode.
建议:
- 暂时只使用v1.8.4版本(经项目长期使用,相对较为稳定)
- 不建议使用1.9.2到1.11.2期间版本,还有其他bug
- 升级到最新的情况下,使用Simulate Groups模式进行开发
- 等待官方后续改进
感谢题主黄程@UWA问答社区提供了回答
Rendering
Q:在Unity中自动展开UV2(Generate Lightmap UVs),会造成个别物体的Mesh中顶点个数增加。
我自动展开的一个地面,顶点数从134变成136,如果不展开UV2,是没有问题的。请问,有什么办法可以在展开UV2时,不增加顶点个数吗?
在导入FBX模型时,没有勾选优化Mesh和其他影响顶点的一些选项。
A:因为有时候2个面片对应到Lightmap上2个不连续区域,而这两个面片上的顶点可能共享,因此需要拆开成2个顶点,其他数据一致,但是UV2不同。属于正常现象。想要不增加,除非美术手动设置UV2并导出,即便如此,如果模型在一些面是包围闭合的,也很难保证顶点不重复。其实这个时候是顶点在Maya等工具内已经做了增加后导出。Unity内可能看不出变化。
感谢黄程@UWA问答社区提供了回答
Build
Q:有没有什么办法可以提升Unity编辑器中代码的编译速度?我们现在每修改一次代码,等待的编译时间都将近半分钟。
A1:对于大型项目来说,这确实是大家经常遇到的情况。一般来说,Unity Editor会按照脚本的依赖关系编译代码,其主要分为以下四个步骤:
- 编译Standard Assets、Pro Standard Assets和Plugins文件夹中的Runtime Script;
- 编译以上三个文件夹中Editor文件夹下的Script;
- 编译项目中所有剩余的Runtime Script(Editor文件夹以外Script);
- 编译剩余Script(即Editor文件夹中Script)。
知道了Unity编辑器的脚本编译特性后,我们则建议研发团队可以将一些长时间不需要改动的脚本代码(比如各种插件代码)放入到Standard Assets、Pro Standard Assets或Plugins文件夹中,这样这些代码只需要编译一次,后续的时间就都能节省下来。
有朋友做过测试,在他们的项目中经过上面的改动,原来项目每次的编译时间从23s下降到7s。想想看,这将节省你和你的团队多少时间!
推荐插件:Mad Compile Time Optimizer
推荐阅读:《优化Unity项目编译速度》
感谢题主Jessica@UWA问答社区提供了回答
A2:添加程序集定义:https://docs.unity.cn/cn/2020.2/Manual/ScriptCompilationAssemblyDefinitionFiles.html
感谢wangzuxiong@UWA问答社区提供了回答
A3:拆分工程编译成不同的DLL,Unity 2017后可以使用引擎自带的工具定义成不同的工程。
感谢mrchen@UWA问答社区提供了回答
Rendering
Q:Pixel Context是灰的:
Debug Vertex也是灰色的:
这是为什么呢?
A1:像素调试的Shader里加#pragma enable_d3d11_debug_symbols。
感谢燃野@UWA问答社区提供了回答
A2:官方文档说有说明,只能在D3D11或者D3D12中进行调试:https://renderdoc.org/docs/how/how_debug_shader.html#hlsl-debugging
感谢Xuan@UWA问答社区提供了回答
封面图来源于网络
今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)