共计 3416 个字符,预计需要花费 9 分钟才能阅读完成。
1)子线程 GC 导致主线程函数耗时较高的问题
2)降级 Unity 大版本后,Text 色彩批改问题
3)革除增量式 GC 导致的 Mono 堆内存透露问题
4)多 Pass 合批优化问题
这是第 274 篇 UWA 技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫 10 分钟,认真读完必有播种。
UWA 问答社区:answer.uwa4d.com
UWA QQ 群 2:793972859(原群已满员)
Rendering
Q:在主线程中有十分多的卡顿,从 UWA 的报告中看到很多异样的高耗时,请问可能是什么起因造成的?
A:像下面这样的频繁卡顿,且卡顿函数品种十分多的状况,应该是子线程调配了十分多的堆内存,导致子线程 GC,从而卡住了主线程。当 GC 的时候,主线程可能会处于各种阶段,因而对应阶段的函数耗时就会包含期待 GC 的耗时。能够从 UWA 的 Mono 报告中查看是否有子线程调配了大量的堆内存,通常是由这种(Thread)打头的子线程函数的调配导致的。
感激 han@UWA 问答社区提供了答复
UGUI
Q:从 Unity 4.6.9f1 降级到 Unity 2020.3.2.f1c1。首次 Unity 降级之后 UI 的 Text 色彩批改是失常。当运行一次之后,所有的 Text 色彩都无奈批改了。就算新创建一个新的 Text 也无奈批改。
A:会有多余的 UI-Default 和 UI-DefaultFont 这两个 Shader,删除它们,而后重启 Unity 就好了。
感激芝麻青豆角 @UWA 问答社区提供了答复
Mono
Q:最近在钻研 Mono 堆内存时,发现一帧内调配屡次较大内存,会导致内存无奈被回收。
过程如下:
在同一帧内调用三次调配 100MB 内存的办法,分配内存的变量都是在各自的作用域,在这之后调用 GC.Collect()。发现有较大几率呈现 100MB 或者 200MB 无奈被回收的 Mono 堆内存。通过排查之后发现勾销勾选 Incremental GC 之后,内存就能齐全被发出。
我揣测是每次申请内存的时候会执行一次 GC,革除上一次调配的内存,然而因为应用增量 GC,无奈在本帧实现回收工作。再下一次 GC 的时候,第二次 GC 的回收内容被重置了,导致第二次的 GC 须要被回收的内存就透露了。
不晓得我这么了解是不是对的,心愿大佬们解惑。同时心愿大佬告知有没有方法革除这部分内存。
测试环境:
Unity 2019.4.15c1
Unity 2020.4.15f2
测试平台:
安卓 Mono
以下为测试代码:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Profiling;
public class TestMonoMemory : MonoBehaviour
{void Do()
{CallBack01();
CallBack02();
CallBack03();}
public void CallBack01()
{List<int> i = new List<int>(1024 * 1024 * 100 / 4);
//CallBack02();}
public void CallBack02()
{List<int> i = new List<int>(1024 * 1024 * 100 / 4);
//CallBack03();}
public void CallBack03()
{List<int> i = new List<int>(1024 * 1024 * 100 / 4);
}
public string text;
private void OnGUI()
{GUILayout.Label("Allocated Mono heap size :" + Profiler.GetMonoHeapSizeLong() / (1024 * 1024) + "MB");
GUILayout.Label("Mono used size :" + Profiler.GetMonoUsedSizeLong() / (1024 * 1024) + "MB");
GUILayout.Label("Total Reserved memory by Unity:" + Profiler.GetTotalReservedMemoryLong() / (1024 * 1024) + "MB");
GUILayout.Label("- Allocated memory by Unity:" + Profiler.GetTotalAllocatedMemoryLong() / (1024 * 1024) + "MB");
GUILayout.Label("- Reserved but not allocated:" + Profiler.GetTotalUnusedReservedMemoryLong() / (1024 * 1024) + "MB");
if (GUILayout.Button("DO"))
{Do();
}
if (GUILayout.Button("DO1"))
{CallBack01();
}
if (GUILayout.Button("DO2"))
{CallBack02();
}
if (GUILayout.Button("DO3"))
{CallBack03();
}
if (GUILayout.Button("GC"))
{System.GC.Collect();
}
}
}
A:通过题主的办法,我也复现了该问题。我还是比拟同意你的了解的。
Unity 官网的一篇对于增量 GC 的博客也写了该办法的弊病:
它的失常运行是须要前提的,那就是在 GC 期间这些被标记为“须要清理的内存”都放弃不变。如果在 GC 期间变动了,比方频繁调配大量内存,那么就须要从新标记一遍,而这个阶段可能会有意想不到的 bug 产生。内存透露很可能就是产生在这个阶段(我也只是猜想)。
不过集体感觉增量 GC 依然是一个良好的尝试,尽管它只是测试阶段,也存在着一些问题,然而以前的 Boehm-Demers-Weiser garbage collector 很容易引起高耗时峰值从而造成卡顿,而分代式 GC 正是为了加重峰值的影响,尽量确保流畅性。
能够参考官网博客:https://blog.unity.com/techno…
该答复由 UWA 提供
Rendering
Q:游戏应用简略的 Mesh 显示几十张扑克牌,为了成果,材质 Shader 应用了 2 个 Pass,其中一个是拉伸做边缘成果,然而因为是多 Pass,即便是雷同的材质和贴图,还是不能动静合批,求教这种状况有没有什么优化计划?
1. 不能合批,然而材质是雷同的,程序渲染过程中是否有什么状态切换的耗费?
2. 是否应用两个 Mesh,不同的材质,Shader 都应用单 Pass,区别是一个 Mesh 是失常显示,一个 Mesh 仅仅做拉伸边缘成果,实践上是不是不超过顶点数的状况下能够两次动静合批?
A1:Unity BuiltIn 渲染管线不反对多 Pass 合批,多 Pass 的 Shader 通过 Set Pass call 一一渲染每个 Pass 后才会持续渲染下一个 Object 反复一遍,所以会产生比拟多的 Draw Call。
更好的方法就是用自定义的渲染管线的形式渲染多个 Pass。在渲染第一个 Pass 的时候,把所有的 Object 一次性全都渲染了,渲染结束之后通过一次 Set Pass Call 去渲染下个 Pass,能够试下 URP 渲染管线。
感激星傲蝶恋 @UWA 问答社区提供了答复
A2:题主说的第二点是比拟惯例的做法,要留神的是为了避免 Draw Call 的交叉,须要调整这两种渲染的 RenderQueue,将他们对应的 RenderQueue 错开。
感激 Xuan@UWA 问答社区提供了答复
20211108
更多精彩问题等你答复~
- Unity 增量打包 AssetBundle 没变动的资源也会被从新打包
- 在模型有 UV2 的状况下开启 Generate Lightmap UVs
- 如何实现 AAB 包的增量更新
封面图来源于网络
明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在 UWA 问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官网技术博客:blog.uwa4d.com
官网问答社区:answer.uwa4d.com
UWA 学堂:edu.uwa4d.com
官网技术 QQ 群:793972859(原群已满员)