【Unity填坑日记】UGUI崩溃巨坑:UI::CanvasRenderer::SyncDirtyElements

在使用UGUI的项目中经常遇到诸如

0x0000000140044A66 (Unity) Unity::GameObject::IsActive
0x00000001411B2E73 (Unity) UI::CanvasRenderer::SyncDirtyElements
0x00000001411BFAC9 (Unity) UI::CanvasManager::UpdateDirtyRenderers
0x00000001411BD336 (Unity) UI::Canvas::UpdateBatches
0x00000001411BE11C (Unity) UI::CanvasManager::WillRenderCanvases
0x00000001403B6C8C (Unity) PlayerLoop
0x0000000140B98C3C (Unity) Application::UpdateScene
0x0000000140B9A6F9 (Unity) Application::UpdateSceneIfNeeded
0x0000000140BA0C84 (Unity) Application::TickTimer
0x0000000140DD1197 (Unity) RelaunchUnity
0x0000000140DD277B (Unity) WinMain
0x00000001414EB994 (Unity) read
0x00000000778B59BD (kernel32) BaseThreadInitThunk

的错误,而且最要命的是,一般不在Editor上出现,一般是在iOS、ANDROID真机上小概率随机出现。而一出现就直接游戏崩溃,一发入魂。。

这个问题从unity5.1开始一直困扰到5.3.5p3都没有得到彻底解决,在更新到5.3.5p3后发现该问题居然能在editor出现了。于是花了一整晚时间找这个原因……

根据unity的出错信息,大概猜测是死在了render一个已经销毁的UI element

通过检查代码,发现我们的一个清空Transform下所有子物体的写法如下:

public static void DestroyChildren(Transform transform) {
    int childCount = transform.childCount;
    for (int i = childCount - 1; i >= 0; --i) {
        var go = transform.GetChild(i).gameObject;
        GameObject.Destroy(go); 
    }
    transform.DetachChildren();
}

怀疑是Destroy后,Unity存在一个BUG导致CanvasRenderer还继续访问了该物体(已经为NULL)

修改代码如下后,问题解决

    public static void DestroyChildren(Transform transform) {
        int childCount = transform.childCount;
        for (int i = childCount - 1; i >= 0; --i) {
            var go = transform.GetChild(i).gameObject;
            go.SetActive(false);

            //by CG:如果不延迟释放,则会crash:UNITY BUG:UI::CanvasRenderer::SyncDirtyElements
            GameObject.Destroy(go, 0.3f); 
        }
        transform.DetachChildren();
    }

我只能说……此处太坑……

猜你喜欢

转载自blog.csdn.net/rcfalcon/article/details/51649980