Search Unity

TextMesh Pro Huge garbage generated (1.6Mo per frame) when changing (a lot of) texts

Discussion in 'UGUI & TextMesh Pro' started by Gladyon, Dec 19, 2019.

  1. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    389
    Context:
    I have a ScrollView which is heavily relying on pooling in order not to have more items in memory than necessary.
    These items display texts, some of them long, some of them very short, depending on the item.
    I am using TextMeshPro with the 'SetText(StringBuilder)' method in order to reduce the garbage generated.


    Summary:
    I have 2 different problems:
    - the 'SetText(StringBuilder)' method is generating garbage in the editor
    - each frame (when scrolling), I have about 1.6Mo of garbage generated by the 'TMP_TextInfo.Resize()' method


    Problem 1:
    Here, the problem isn't that serious, I do not care about garbage in the editor, but there is another problem.
    In the code, I saw that the garbage is coming from the 'm_text = text.ToString();' which is only executed in the editor.
    I suppose that it's to be able to see the text in the editor. No problem here.
    But, what about release? If someone use the '.text' field, it will not be updated. Am I right?
    In that case, there is a bug, because something which works perfectly in the editor will fail consistently in release.
    I suppose that the '.text' field shouldn't be accessible from release, with some associated documentation and warnings.


    Problem 2:
    OK, this is the real one, the one which generates 1.6Mo of garbage per frame.
    I have managed to remove that garbage by removing the resizing when the allocations are excessive in the 'TextMeshProUGUI.SetArraySizes()' method (I found it 2 times, I may have missed some other ones).

    From my understanding, it's there to avoid consuming too much memory for mobile.
    But in some cases (PC for example), we do not care about the total memory, but we do care about 1.6Mo of garbage generated per frame.

    From what I saw in the code (but I may be mistaken as I looked into it only for a couple of minutes), it would be very easy to add a checkbox to enable/disable that resizing when the allocations are excessive.


    Conclusion:
    So my question are:
    - could something be done about the '.text' field not updated in release? (if my analysis is correct of course, if it isn't then disregard that question)
    - could a checkbox to enable/disable the internal arrays resizing be added in a future version?
     
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,596
    This is by design and exactly for the reason you stated which is to keep the .text property in the Editor in sync with the underlying text coming from SetText.

    The .text property or SetText() functions are used to provide the source text to TMP which is then parsed and stored into an internal data structure for processing. Once parsed, all these source input path end up the same at Runtime.

    The only potential Gotcha at runtime if a developer was using SetText() would occur if they were to subsequently do something like "string s = m_TextComponent.text;" where in this case, .text would contain whatever it was previously set to but not the content of SetText(). This is not an issue as developers using SetText() to avoid string allocations would be unlikely to subsequently use a string the would generate allocations to store the text which they just provided via StringBuilder.

    These allocations are the result of the internal buffers used in the process of parsing, layout and rendering of the text being resizing to handle the provided text. With small amounts of text, this resizing is not usually an issue. However, with larger amounts of text it becomes and issue and something that I plan on addressing short term.

    Item #1 is by design and should not be an issue. It would only be an issue if you were trying to retrieve the content of the text provided via SetText() but then using the .text property to look it up.

    Item #2 is something that I will be addressing. This will be better handled internally by TMP and not require a check box or anything.
     
    slice3d likes this.
  3. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    389
    Thank you for your answers.


    For information, the item #1 caused me some trouble.
    I did used 'SetText(StringBuilder)' and after I did used '.text'. I had to save the string myself as a StringBuilder and add some code to compare 2 StringBuilder (because the 'Equals()' method doesn't check the actual content...).
    That said, you're right, using '.text' was only a temporary solution as it generated garbage.

    Anyway, I think that item #1 should be addressed, at least with a clear comment/documentation indicating that it will not work and that it is not a bug, because it is not behaving as it should.

    Easy to implement solution for '.text.:
    That said, I think that a much better way would be to add a Boolean indicating if the current '.text' is upd-to-date or not.
    When accessing the '.text' property, the Boolean is checked, and if 'false', then you create a 'String' using you internal Char buffer and set the Boolean to 'true' (the same Boolean is set to false each time 'SetText(StringBuilder)' is called, and maybe also when some 'SetText(Char[])' or similar methods you could have is called).

    That way, the garbage would only be generated if the 'get' property of '.text' is accessed (which is perfectly normal behaviour).
    But most importantly, it would behave as intended, with '.text' always returning the correct string.


    As for Item #2, I will wait for your internal solution with eagerness.
    I am indeed using some quite long texts, and the performances in release build are horrible(a drop from 80 to 20 FPS).
    I cannot profile the build for now due to technical problems, but from what Ive seen the garbage generate is playing its part, along with the 'GetPreferredValues()', but that's another matter. If I have more details I'll make another post.
     
  4. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    452

    Hi @Stephan_B, I'm getting a large amount of garbage allocated due to TMPro resizing:

    upload_2023-7-15_17-4-36.png

    I would like to know the current state of TMPro in regards to this issue, and if possible, any tips to work around it since the garbage generated is a bit too much (when just handling a few text components). Thank you.