这是第475篇UWA技术知识分享的推送,精选了UWA社区、UWA AI问答的热门话题等技术知识点,助力大家更全面地掌握和学习。
UWA社区主页:community.uwa4d.com
UWA QQ群:793972859
本期目录:
持续性字符串拼接:每帧5KB从何而来?
碎片占比超50%:Mono内存碎片化怎么避免?
本次推送的实战案例来自于使用UWA服务的项目的真实且典型的问题。UWA将关键线索、定位路径与处理建议整理成了可复用的案例笔记,便于大家快速对照、排查自身项目中的同类问题。
实战案例
Q:GOT Online Mono模式报告显示,我们项目Mono堆内存中存在持续的字符串拼接现象,这是什么原因导致的,该怎么定位和优化?
A:看到在UIPanel.LateUpdate中全程出现持续的String.Concat的分配,出现这种现象常见的原因包括:UI元素的name赋值;Panel取名等逻辑里存在字符串拼接;业务打点日志中频繁做字符串拼接;Shader查找流程中存在名称拼接操作等。优化原则是避免每帧进行字符串拼接操作,将拼接结果缓存复用,减少Mono堆内存临时分配,字符串拼接逻辑本身也不应放在游戏核心循环的热路径中。
从当前报告数据来看,仅仅是 持续字符串拼接每帧新增约5KB临时垃圾分配,再加上NGUI中一些其它分配,累计每万帧分配量超90MB。UWA推荐Mono报告中Top10函数平均每10k帧分配堆内存总和小于50MB,目前仅一个UIPanel.LateUpdate就已超出推荐值范围,因此要对以UIPanel.LateUpdate为首的多个分配较高的函数进行排查。
排查方法是在Mono模式报告中,按"分配视角"查看函数堆栈,定位累积分配最多的叶子函数,追溯其调用路径。另外还可以利用报告里的倒序调用分析模块,它能直接定位高分配的底层问题函数,帮我们省去逐层排查的繁琐操作,例如上述的String.Concat问题就能直接定位到。
Q:另外我们还在报告中发现Mono堆内存出现了一个52MB的大数组,但查不到具体来源,该怎么排查?
A:我们可以从这份Mono模式报告看到,这个byte数组从测试开始就存在,但无法获取其分配堆栈。这是因为在 UWA性能采集启动前( 游戏初始化阶段 ), 该数组就已经完成分配了,所以追踪不到来源。
需要我们采集数据的时候,在SDK面板上点击Direct Mode进行采集。点击Direct Mode后会在开始采集时杀掉进程并重新启动游戏,从游戏启动开始,Mono分配的整个生命周期就会被采集,这样就可以追踪到之前无法获取堆栈的大数组来源了。
这类大数组常见来源多为大型配置表、场景标记数据等。
若确认是配置表导致,可优化两点:
将配置表数据下沉至Native层存储,不占用Mono堆内存,规避GC压力与回收耗时;
改用更紧凑的数据结构,例如用bit替代int存储标记信息,进一步缩减内存占用。
实战案例
Q:Mono内存碎片化比较严重,怎么避免,有什么优化建议?
A:从报告来看,碎片占比高达112MB/219MB(约51%),在堆内存分配释放较为频繁的项目中,UWA也常观察到对象实际占用的部分和碎片会逐渐趋于相等。 Unity的Boehm GC为非压缩回收器,不会主动整理Mono堆碎片,频繁产生临时内存分配,是造成碎片化的主要原因; 即便GC回收空闲内存,已形成的碎片也无法合并成连续大块,只能被小对象复用,因此要尽量减缓碎片占比逐渐上升的趋势。
我们可以从以下三个方面进行优化:
第一,减少临时分配,避免在热路径上进行字符串拼接、容器扩容等操作;
第二,对频繁创建销毁的对象使用对象池复用;
第三,对可预期的容器预分配足够容量,避免运行时扩容。
无论是社区里开发者们的互助讨论,还是AI基于知识沉淀的快速反馈,核心都是为了让每一个技术难题都有解、每一次踩坑都有回响。希望这些从真实开发场景中提炼的经验,能直接帮你解决当下的技术卡点,也让你在遇到同类问题时,能更高效地找到破局方向。
封面图来源于网络
今天的分享就到这里。生有涯而知无涯,在漫漫的开发周期中,我们遇到的问题只是冰山一角,UWA社区愿伴你同行,一起探索分享。欢迎更多的开发者加入UWA社区。
UWA官网:www.uwa4d.com
UWA社区:community.uwa4d.com
UWA学堂:edu.uwa4d.com
点击下方名片关注我们,将我设为星标,及时接收小编每日推送哦,性能优化不迷路~
近期精彩回顾
热门跟贴