Search Unity

Bug UGUI GraphicRaycaster field "m_RaycastResults" cause asset memory leak with Addressable

Discussion in 'UGUI & TextMesh Pro' started by h2ojunjun, Feb 7, 2024.

  1. h2ojunjun

    h2ojunjun

    Joined:
    Nov 24, 2019
    Posts:
    2
    Unity Version : 2022.3.13f1c1
    UGUI Version: 1.0.0
    Addressable Version 1.21.19
    Platform:Android
    Tool:Memory Profiler

    Preparation to reproduce:
    1.Prepare two UI perfabs:First UI looks like login panel,second UI look like game's main panel.
    2.Prepare some sprite,one sprite(we call it A) will be used by enter button in login panel,other sprites will be used in main panel.
    3.Prepare two scene,one scene for login panel,one for main panel
    3.Make these sprites in a same addressable group and pack them together to make them in a same asset bundle.

    Steps to reproduce:
    1.Open the first scene and login panel.
    2.Click enter button to close this UI(unload the prefab and destroy the instance) and then load the second scene with paramter LoadSceneMode.Single,after this,open main panel.(open scene and main panel is executed by code!)
    3.Do not click anywhere!
    4.Open Memory Profiler and capture a snapshot.

    You will see sprite A on enter button is still in memory even the UI attached by it is already destroyed!
    here are the snapshots:
    upload_2024-2-7_15-47-13.png
    Then we look at the references:
    upload_2024-2-7_15-49-5.png
    We can see here is a List<Graphic> reference the Image component on the enter button.but why?here is the reason:
    in GraphicRaycaster.cs line.239:
    upload_2024-2-7_15-52-45.png
    In this code,we first clear m_RaycastResults,the we add some elements in the list,but this method would only be called when user click on the screen.
    In this case,we could analyze the progress of our steps:
    1.when we open the login UI,the sprite will load in the memory with instantiation of the UI prefab.
    2.when we click enter button,GraphicRaycaster will calculate the RayCasting.the enter button's image component will be added in the list m_RaycastResults,and then the UI instance will be destroyed,the UI Prefab also destroyed.
    3.then we load the second scene with parameter LoadSceneMode.Single.Unity will call Resources.UnloadUnusedAssets internally.But it can't clear the sprite A because the list m_RaycastResults still references the sprite.
    4.Then we can click on the main panel,m_RaycastResults will break the reference.But sprite A still can not be unload because sprite A is still referenced by the asset bundle cause some sprites in bundle now is loaded.

    After all,in the code previously showed in the picture before.There is no difference between we put m_RaycastResults.clear() at the beginning of the method and we put it and the end.But UGUI choose to put it at the beginning,this causes a bad references to these raycastable image.If user do not click screen again,the references remains forever!If we put it at the end,Resources.UnloadUnusedAssets will clear these sprite when we load the second scene!