Unity中Instantiate实例化物体卡顿问题的解决

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

Unity中Instantiate实例化物体卡顿问题的解决

LLLLL__   2020-10-28 我要评论

一、前言

当在执行多次Instantiate实例化物体时,会卡顿严重甚至在移动端会导致程序崩溃
因为Instantiate会产生大量的GC,使CPU过高,导致崩溃

下面是一段测试代码:当我们按下按键时实例化100000个预制体

using UnityEngine;
 
public class Test : MonoBehaviour
{
  public GameObject prefab;
 
  private void Update()
  {
    if (Input.GetKeyDown(KeyCode.A))
    {
      Generate();
    }
  }
 
  private void Generate()
  {
    for (int i = 0; i < 100000; i++)
    {
      Instantiate(prefab);
    }
  }
}

运行后通过profiler查看性能

发现在实例化物体的那一帧产生了3.8MB的GC,而正常来说每帧的GC不能超过2KB,产生如此高的GC在移动端会导致内存溢出从而崩溃闪退。更可怕的是这一帧用时1519.24毫秒也就是1.5秒所以程序在此帧会出现卡顿现象

二、解决方法

卡顿或程序崩溃的原因就是在某一帧中产生了大量的GC
所以可以把一帧的操作分帧进行

using UnityEngine;
using System.Collections;
 
public class Test : MonoBehaviour
{
  public GameObject prefab;
 
  private void Update()
  {
    if (Input.GetKeyDown(KeyCode.A))
    {
      StartCoroutine(Generate());
    }
  }
 
  private IEnumerator Generate()
  {
    int tempCount = 0;
    for (int i = 0; i < 100000; i++)
    {
      if (tempCount <= 5000)
      {
        Instantiate(prefab);
        tempCount++;
      }
      else
      {
        tempCount = 0;
        yield return new WaitForEndOfFrame();
        Instantiate(prefab);
      }
    }
  }
}

三、协程中几种yield reutrn的执行顺序

using UnityEngine;
using System.Collections;
 
public class Test : MonoBehaviour
{
  private void Start()
  {
    StartCoroutine(WaitForNull());
    StartCoroutine(WaitForEndFrame());
    StartCoroutine(Wait0());
    StartCoroutine(WaitForFixedUpdate());
  }
 
  private IEnumerator WaitForNull()
  {
    Debug.Log("[1]WaitForNull:" + Time.frameCount);
    yield return null;
    Debug.Log("[2]WaitForNull:" + Time.frameCount);
  }
 
  private IEnumerator WaitForEndFrame()
  {
    Debug.Log("[1]WaitForEndFrame:" + Time.frameCount);
    yield return new WaitForEndOfFrame();
    Debug.Log("[2]WaitForEndFrame:" + Time.frameCount);
  }
 
  private IEnumerator Wait0()
  {
    Debug.Log("[1]Wait0:" + Time.frameCount);
    yield return 0;
    Debug.Log("[2]Wait0:" + Time.frameCount);
  }
 
  private IEnumerator WaitForFixedUpdate()
  {
    Debug.Log("[1]WaitForFixedUpdate:" + Time.frameCount);
    yield return new WaitForFixedUpdate();
    Debug.Log("[2]WaitForFixedUpdate:" + Time.frameCount);
  }
 
  private void Update()
  {
    Debug.Log("update");
  }
 
  private void FixedUpdate()
  {
    Debug.Log("FixedUpdate");
  }
 
  private void LateUpdate()
  {
    Debug.Log("LateUpdate");
  }
}

经过测试,得出以下结论

  • WaitForFixedUpdate在一帧的FixedUpdate后Update前调用
  • WaitForNull和Wait0在一帧的Update后LateUpdate前调用
  • WaitForEndFrame在会在一帧的LateUpdate后调用

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们