Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug Memory management is broken in Android if >500 MB memory usage (ie. any UI Toolkit build)

Discussion in 'UI Toolkit' started by mikejm_, Dec 4, 2022.

  1. mikejm_

    mikejm_

    Joined:
    Oct 9, 2021
    Posts:
    346
    I have been trying to track down a problem the past few days and I think I have it narrowed down. It seems Unity memory management in general becomes crippled in Android if you go past around 500 MB of memory usage.

    Here is a simple 80 line script which I wrote to show it, attached to a GameObject with a UI Document with a blank UI Document and default Panel Settings set to scale by screen size (width).

    Code (csharp):
    1. public class App : MonoBehaviour {
    2.  
    3.     ConstructedElement bgVE;
    4.     public event Action buttonClick = delegate{};
    5.     public bool turnOnMemoryWaster = false;
    6.     private Color32[] arrayBig;
    7.  
    8.     private void Awake() {
    9.         VisualElement rootVE = gameObject.GetComponent<UIDocument>().rootVisualElement;
    10.  
    11.         IEnumerator buildIt() {
    12.             yield return null;
    13.  
    14.             bgVE = new ConstructedElement();
    15.             bgVE.style.width = bgVE.style.height = new Length(100, LengthUnit.Percent);
    16.             rootVE.Add(bgVE);
    17.  
    18.             arrayBig = new Color32[10000 * 10000];
    19.  
    20.         }
    21.  
    22.         Coroutine creationCo = this.StartCoroutine(buildIt());
    23.  
    24.         IEnumerator wasteTime() {
    25.             bool trueFacts = true;
    26.             while (trueFacts) {
    27.                 int[] fakearray = new int[10000];
    28.                 yield return null;
    29.             }
    30.         }
    31.         StartCoroutine(wasteTime());
    32.  
    33.     }
    34.  
    35.     // Start is called before the first frame update
    36.     Texture2D memoryWaster;
    37.     Color32[] colorWaster;
    38.     void Start()
    39.     {
    40.         if (turnOnMemoryWaster) {
    41.             memoryWaster = new Texture2D(5000, 5000);
    42.             colorWaster = memoryWaster.GetPixels32();
    43.         }
    44.  
    45.     }
    46.  
    47.     // Update is called once per frame
    48.     void Update()
    49.     {
    50.         if (Input.GetMouseButtonDown(0)) {
    51.  
    52.             int texels = 5000 * 5000;
    53.             var texelsCopy = System.Buffers.ArrayPool<Color32>.Shared.Rent(texels);
    54.             System.Buffers.ArrayPool<Color32>.Shared.Return(texelsCopy);
    55.  
    56.         }
    57.     }
    58. }
    59.  
    60. public class ConstructedElement: VisualElement {
    61.     VisualElement bgVE;
    62.     public Texture2D bgT2D;
    63.  
    64.     public ConstructedElement() {
    65.         bgVE = new VisualElement();
    66.         bgVE.style.width = bgVE.style.height = new Length(100, LengthUnit.Percent);
    67.         bgT2D = Resources.Load<Texture2D>("bg");
    68.         bgVE.style.backgroundImage = bgT2D;
    69.         this.Add(bgVE);
    70.  
    71.     }
    72. }
    I am testing with a high end phone (Samsung S21 Ultra). If I build to the device with Profiler attached I can observe two patterns of behavior.

    1) If the UI Document attached to the script Game Object is disabled (and the turnOnMemoryWaster bool is false), memory usage is generally low ~200 MB and clicking to trigger the Rent/Return of an ArrayPool proceeds roughly as expected. Memory is released and generally usage is relatively stable:

    memory bug ui document disabled low memory state.PNG
    (Each red spike corresponds to a screen tap.)

    2) By contrast, if I enable the UI Document, memory usage at baseline is around 495 MB and this where things start getting messy. Now every time I click the screen, I have incremental climbing of the memory usage until eventual crash:

    memory bug ui document enabled 1.PNG
    It is not always this perfectly linear in how it rises but it will always end up >1 GB if you click enough times.

    I have found that disabling the UI Document on the Game Object and then wasting some memory with the turnOnMemoryWaster bool will still create a similar pattern, but it won't rise quite as quickly. Thus I am not thinking it is specifically due to the UI Document, but rather just due to a problem that occurs in Unity on Android once you get over 500 MB memory usage in general. Unfortunately, this is virtually any UI Toolkit project though.

    Is it known or expected that this should be the case? Are System.Buffers.ArrayPool<Color32>.Shared.Rent & Return known to be unsafe in Android with Unity?

    I got into the Rent & Return path because recurrently using Texture2D.GetPixels32() and Texture2D.SetPixels32() also create this memory rise until crashing on Android (which I presumed was heap fragmentation). In theory, copying texels like this should be memory stable although as shown above it is certainly not:

    Code (csharp):
    1.    var texels = tex.GetRawTextureData<T>();
    2.    var texelsCopy = System.Buffers.ArrayPool<T>.Shared.Rent(texels.Length);
    3.    Unity.Collections.NativeArray<T>.Copy(texels, texelsCopy, texels.Length);
    4.  
    5.    //when done:
    6.    System.Buffers.ArrayPool<Color32>.Shared.Return(texelsCopy);
    The only solution I have come up with is to make my own static List<Color32> that I can use for temporary texture math and let it hold some memory always, but I find it concerning that memory management is this messed up, as it makes me concerned that other problems may show up elsewhere as well from it. It seems like a workaround for a deeper problem.

    Thanks for any thoughts. I can submit a bug report project if it is of any interest.
     
    Last edited: Dec 4, 2022
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,222
  3. mikejm_

    mikejm_

    Joined:
    Oct 9, 2021
    Posts:
    346
    Sure. Thanks. Bug report made: IN-24891

    Looking forward to a resolution or some answers. I will keep working on other things in the mean time. Thanks again.
     
    karl_jones likes this.