起因:用Unity2021.3.15f1打的项目在外网发现托管堆无限增长
一.排查原因
通过MemoryProfiler排查发现是Graphic对象泄露
排查Unity 2021.3.15f1的UGUI逻辑,发现是graphic节点移动之后,canvas释放不正确。
原因是2021.3.15f1 UGUI对IndexedSet和CanvasRegister两个类做了缓存优化。
具体原因如下:
1.Unity 2020 UGUI graphic移动父节点Canvas流程
graphic节点移除之后会直接remove
2.Unity 2021 UGUI graphic移动父节点Canvas流程
graphic节点移除会把graphic移到队列最后,并不会直接移除
二.构建Demo测试用例
测试代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Profiling;
using System;
public class MemoryTest : MonoBehaviour
{
public GameObject canvas1;//canvas1节点
public GameObject __canvas2; //canvas2 原型
public GameObject __graphic; //子节点graphic 原型,里面加了很多Text对象增加内存泄露直观表现
public Text text; //显示内存信息
// Start is called before the first frame update
IEnumerator Start()
{
while (true)
{
//创建canvas2
var canvas2 = GameObject.Instantiate(__canvas2);
//在canvas2节点下创建graphic
var graphic = GameObject.Instantiate(__graphic,canvas2.transform);
yield return new WaitForSeconds(0.2f);
//image1节点移动到canvas1
graphic.transform.SetParent( canvas1.transform);
//销毁canvas2和graphic
Destroy(canvas2);
Destroy(graphic);
yield return new WaitForSeconds(0.1f);
//显示托管堆内存
text.text ="Mono Used Size:"+ Math.Round(Profiler.GetMonoUsedSizeLong()*0.00000095367431f,2)+" MB";
//调用内存释放GC
System.GC.Collect();
Resources.UnloadUnusedAssets();
}
}
}
测试场景:
运行结果:
内存随着时间不断增加
三.修复UGUI
根据排查原因,修复UGUI
1.修改UGUI源码
修改其中CanvasRegister代码
2.运行Demo测试
内存不再上升,修复成功。
四.总结
这个UGUI内存泄露bug过于离谱,目前只检查了unity2021.3.15f1和unity2021.3.8f1有问题,2020暂时没发现。
如果是我判断错误希望知情人士讲解一下。