1)抓取手机端变体组合思路构想
2)如何革除 File.ReadAllBytes 产生的内存泄露
3)atlas.GetSprite(name) 内存泄露
4)Unity 版本更新后 Odin 插件序列化报错
这是第 303 篇 UWA 技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫 10 分钟,认真读完必有播种。
UWA 问答社区:answer.uwa4d.com
UWA QQ 群 2:793972859(原群已满员)
Shader
Q:对于变体收集的问题,PC 端编辑器尽管自带收集,然而毕竟运行的时候是 Editor 环境,与实在挪动端环境相差甚远。Warmup 只会预加载列表中的组合,非 Shader 打包的全副组合。这样如果收集的变体非实在环境,只会白白浪费 CPU 及 GPU 显存,等实在渲染的时候发现之前提交的组合非挪动端所须要的,须要从新 Warmup。
再者,如果做品质划分,比方粗劣画面开动静暗影,晦涩机型关。这样会产生两套组合。实践上应该分成两个 SVC,而 PC 是只能保留所有的变体列表。
综上,我构想解决方案就是通过实在跑手机,抓取手机的应用数据,来划分到不同的列表中,这样应该是最实在牢靠的。
为了实现这个构想,须要能找到如何取得提交的变体数据,已知能够在 profiler-CPU-Timeline 模式下的 Shader.CreateGPUProgram 外面的 meta_data 外面能够拿到。
通过 CS 源码剖析到 NativeProfilerTimeline 这个控件是绘制 Timeline 的外围类。NativeProfilerTimeline.GetEntryInstanceInfo 这个函数能够拿到对应的 meta_data。
然而这个类是 C ++ 底层写的,C# 只是 Draw 去提交绘制。GetEntryAtPosition 去依据鼠标地位来取得 Entry,代码无奈反射到 EntryIndex。当初陷入了死胡同。
大家有解决办法或者新的思路吗?最好能获取手机上的变体列表。
A:能够在 Graphics 面板上勾选这个 Log Shader Compilation:
编辑器下 Console 连贯真机,这样就能够在触发 Shader.CreateGPUProgram 时看到相应的 Log:
Autoconnected Player Compiled shader: Unlit/TestShader, pass: <unnamed>, stage: all, keywords FOG_EXP2
感激宗卉轩 @UWA 问答社区提供了答复
Memory
Q:最近我的项目玩的工夫长了,内存始终暴增。在查看过程中,发现游戏中用了一个 File.ReadAllBytes 办法来读取几个 5~10MB 不等的二进制数据,加载完数据曾经复制 null,然而 Mono 还是始终增长,调用 GC 都开释不掉。
实践上来讲这个数组业务层曾经没有援用了。然而,用 Memory Profiler 查看,内存还始终在。求教一下,有没有人晓得革除的办法?
Unity 版本 2019.4.9
A1:缓冲区不必每次都 new 一个。
感激 jim@UWA 问答社区提供了答复
A2:如果是 Mono 版本的 APK,能够试试 IL2CPP。如果 IL2CPP 版本没有这个问题,应该是遇到 Mono 的 Bug 了,一次性调配较多的堆内存,会概率呈现这些调配的堆内存无奈回收的问题。
感激 Xuan@UWA 问答社区提供了答复
A3:Boehm GC 自身的缺点导致的,能够搜搜 BlackList,若有源码,能够有很多种防止或小修的改法;若没源码能够尝试:
- 缩小字典中 Struct 当 Key;
- 拆小文件,重写 File 的接口,复用内存。
感激 kent@UWA 问答社区提供了答复
Script
Q:Unity 版本 2019.4.23,发现在频繁调用 atlas.GetSprite(name) 时会内存泄露,只增不减,直至解体!有人遇到过这问题吗?请问有什么好的解决办法吗?
A1:如果不思考引擎自身 Bug 的状况下,内存泄露大部分都是援用没有解决好。可能有些中央还在应用这些资源,只是没关联上,导致无奈回收这部分资源。所以能够着重先排查这部分性能。
感激廖武兴 @UWA 问答社区提供了答复
A2:
//
// 摘要:
// Clone the first Sprite in this atlas that matches the name packed in this atlas
// and return it.
//
// 参数:
// name:
// The name of the Sprite.
public Sprite GetSprite(string name);依据这段的说法是 Clone,也就是说每次调用 GetSprite,都会执行一次克隆操作,并且不会主动开释。
那么就要用治理脚本做一个缓冲池,反复的 Sprite 间接从池子里获取。并且开释的时候也从该脚本进行开释。
Dictionary<string, Sprite> mSpritePool = new Dictionary<string, Sprite>(); public Sprite GetSprite(string key, SpriteAtlas source) { Sprite result = null; if(!mSpritePool.TryGetValue(key, out result)) {result = source.GetSprite(key); if (result != null) {mSpritePool.Add(key, result); } } return result; }
还能够做 SpriteAtlas 对象的键值对寄存,不便获取和开释。
感激 canyon@UWA 问答社区提供了答复
Script
Q:Unity 版本更新后 Odin 序列化,版本更新后,从 2020.3.21 更新到 2021.3.41 后就呈现这个问题。
A:Odin 仓库有个相似的问题,在 3.0.13.0 版本修复了,试一下降级插件版本:
https://bitbucket.org/sirenix…
感激羽飞 @UWA 问答社区提供了答复
封面图来源于网络
明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在 UWA 问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官网技术博客:blog.uwa4d.com
官网问答社区:answer.uwa4d.com
UWA 学堂:edu.uwa4d.com
官网技术 QQ 群:793972859(原群已满员)