在 Unity 2022.3 中,为什么我的对象实例化时间经常激增?

问题描述 投票:0回答:1

所以我目前正在创建一个带有程序世界生成的游戏。因此,我经常加载和卸载大量的世界数据。过程如下:

第 1 步:加载块后,它会获得一个线程工作线程,该线程工作线程在单独的线程中从文件中读取数据。 该工作人员还准备“原型对象”,其中包含稍后实例化我的游戏对象所需的大部分数据。这包括诸如用于设置纹理的 Color 数组和用于设置碰撞器的 Vector2 数组之类的内容。

第 2 步:线程完成后,会将完成的原型对象放入 ConcurrentQueue 中,并在主线程中将其出队并用于初始化游戏对象。这包括添加脚本和 SpriteRenderer 作为组件,以及将 createUninitialized 标志设置为 true 来初始化 Texture2D。

第 3 步:创建碰撞器以及将 Color 数组应用于纹理以及随后的 Apply() 调用将在稍后处理(效果很好,但超出了本文的范围)

现在问题来了: 步骤 2 通常需要大约 0.5-5 毫秒。 Screenshot Profiler case 1

但有时它会花费 50-200 毫秒。 Screenshot profiler case 2

如您所见,这种情况或多或少有规律地发生。我首先怀疑垃圾收集器清除与它有关,因为你可以看到它与这里的这个尖峰对齐。但其他人的情况似乎并非如此...... 此外,它似乎与纹理大小无关,因为在此处突出显示的两种情况下,纹理的大小均为 160x160,大多数情况下都是这种情况...

无论如何,这是在突出显示的“创建对象”部分中进行分析的代码:

public static PhixelObject Create(Chunk chunk, Vector3Int chunkPos, List<Vector2> verticies, List<Phixel> perimeterPhixels, Phixel[,] phixelMatrix, GameObject gameObject = null)
{
    //Create create
    PhixelObject phixelObject = Create<PhixelObject>(gameObject);
    //this just creates a new GameObject and adds the script as a component

    //Set Transform
    phixelObject.transform.localScale = new Vector3(Constants.PIXEL_PER_METER, Constants.PIXEL_PER_METER, 1);
    phixelObject.transform.parent = chunk.transform;
    phixelObject.transform.localPosition = new Vector3(chunkPos.x - Constants.CHUNK_SIZE / 2, chunkPos.y - Constants.CHUNK_SIZE / 2, -chunkPos.z);

    //Add Sprite Renderer
    phixelObject.textureRenderer = phixelObject.AddComponent<SpriteRenderer>();

    //"create Texture_x" + phixelObject.dims.x.ToString() + "_y"+ phixelObject.dims.y.ToString()
    phixelObject.tex = new Texture2D(phixelObject.dims.x, phixelObject.dims.y, TextureFormat.RGBA32, -1, false, true);


    return phixelObject;
}

(为了可读性,我用注释替换了手动 Profile.BeginSample() 调用,并删除了未分析的部分)

总的来说,我觉得很奇怪,例如相同的Texture2D初始化连续20次需要0.05毫秒,然后一次或两次需要40毫秒,然后又回到0.05毫秒。

如上所述,纹理大小不能不同,因为它们在大多数情况下都是相同的。 我也没有完全排除 GC 问题,但我已将类更改为结构,将引用类型数组更改为值类型数组,以便更轻松地收集内容。

所以我希望有人知道这里发生了什么, 或者至少可以给我一些找到罪魁祸首的提示。 预先感谢您的任何帮助! :)

编辑:

  • 每帧仅处理一个块
  • 块包含 1-3 个已创建的对象
  • 对于这两个屏幕截图,我选择了一个仅包含一个对象的块,因此生成的对象数量不应成为问题的驱动因素
  • 我一直在尝试在项目之外复制问题,但它似乎并不像用虚拟值实例化相同的对象那么容易。这让我认为它与减慢实例化速度的其他进程有关?但它们不会在分析器中以某种方式可见吗?
  • 奇怪的是,在编辑器中进行分析时,峰值显示为“编辑器循环” Screenshot Profiler case 3
  • 我尝试了深度分析,但结果更令人困惑 Screenshot Profiler case 4 Screenshot Profiler case 5 正如您在第二张图片中看到的,有时是创建纹理调用,有时是字符串分配,有时此 RuntimeType.getFullName() 会导致卡顿。所以我很确定后台发生的其他事情总体上会减慢速度。但我该如何调试呢?
performance unity-game-engine instantiation gameobject texture2d
1个回答
0
投票

所以我现在已经有了一个运行流畅的版本,但需要采取很多步骤才能到达那里。

问题的根源似乎是太多、太大的texture.apply()调用、仍然超载的垃圾收集器以及过去几个月增长的大量意大利面条代码的组合。

答案更复杂,我更详细地介绍了这里 但是 tl;博士:

  • 清理你的代码,你知道它已经过期有一段时间了
  • texture.apply() 调用往往需要一段时间,因此减少它们的使用
  • 使用 ComputeShaders 和 RenderTextures 将对象数量从每个块每个 z 高度层一个对象减少到每个块一个对象
  • 使用 SubUpdate ComputeBuffers 和 BeginWrite 而不是 SetData 将texture.apply() 所做的昂贵的数据复制工作移离主线程
© www.soinside.com 2019 - 2024. All rights reserved.