0

抓取手机端变体组合思路设想 - UWA问答 | 博客 | 游戏及VR应用性能优化记录分享 | 侑...

 1 year ago
source link: https://blog.uwa4d.com/archives/TechSharing_303.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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里面可以拿到。

1.png

通过CS源码分析到NativeProfilerTimeline这个控件是绘制Timeline的核心类。NativeProfilerTimeline.GetEntryInstanceInfo这个函数可以拿到对应的meta_data。

但是这个类是C++底层写的,C#只是Draw去提交绘制。GetEntryAtPosition去根据鼠标位置来获得Entry,代码无法反射到EntryIndex。现在陷入了死胡同。

大家有解决办法或者新的思路吗?最好能获取手机上的变体列表。

A:可以在Graphics面板上勾选这个Log Shader Compilation:

2.png

编辑器下Console连接真机,这样就可以在触发Shader.CreateGPUProgram时看到相应的Log:
Autoconnected Player Compiled shader: Unlit/TestShader, pass: , stage: all, keywords FOG_EXP2

感谢宗卉轩@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/62a9a151898b3a7fa617d2d9


Memory

Q:最近项目玩的时间长了,内存一直暴增。在检查过程中,发现游戏中用了一个File.ReadAllBytes方法来读取几个5~10MB不等的二进制数据,加载完数据已经复制null,但是Mono还是一直增长,调用GC都释放不掉。

3.png

理论上来讲这个数组业务层已经没有引用了。但是,用Memory Profiler查看,内存还一直在。请教一下,有没有人知道清除的方法?

Unity版本 2019.4.9

4.png

A1:缓冲区不用每次都new一个。

感谢jim@UWA问答社区提供了回答

A2:如果是Mono版本的APK,可以试试IL2CPP。如果IL2CPP版本没有这个问题,应该是遇到Mono的Bug了,一次性分配较多的堆内存,会概率出现这些分配的堆内存无法回收的问题。

感谢Xuan@UWA问答社区提供了回答

A3:Boehm GC本身的缺陷导致的,可以搜搜BlackList,若有源码,可以有很多种避免或小修的改法;若没源码可以尝试:
1.减少字典中Struct当Key;
2.拆小文件,重写File的接口,复用内存。

感谢kent@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/6268b7d736a2fd066deabeaa


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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/61e4f27bd8413e18eb85c85b


Script

Q:Unity版本更新后Odin序列化,版本更新后,从2020.3.21更新到2021.3.41后就出现这个问题。

5.png

A:Odin仓库有个类似的问题,在3.0.13.0版本修复了,试一下升级插件版本:
https://bitbucket.org/sirenix/odin-inspector/issues/843/error-with-serializedmonobehaviour-on

6.png

感谢羽飞@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/62b91963b72f303e19830fb5

封面图来源于网络


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK