We’re trying to get the iOS version of our app to not run out of memory. One thing we’re finding is that over time the TMP_CharacterInfo size gets really huge. Over 111MB and counting (6,000 objects).
TextMeshProUGUI also adds 33MB and WordWrapState tack on 32MB. Altogether it’s a killer.
Could you please share any thoughts or tips on what we can do to release all those from memory? We’re running garbage collection pretty consistently, but these guys are still staying stuck. We’re running 2019.4.8f1 and TMP 2.1.1.
Currently, the text parser and layout is owned by each text object. This includes the textInfo which as you point out becomes increasingly memory intensive with growing number of text objects.
This is something that I am well aware of and currently planning on changing in TextCore which will be the new text parsing and layout engine used by TMP, UI Toolkit, and Unity in general. No firm ETA on that yet.
In the meantime, I have the following question.
Are you text objects mostly static? Ie. Once instantiated, does the text change?
We’re in a similar situation with TMP components and WordWrapStates eating a lot of memory (around 16.5 KB each). With a lot of text components in the game, this quickly adds up.
We were wondering where you are going with the “text objects mostly static” question? Are there any optimizations at all we can do to get rid of the WordWrapState allocations? Turning off word wrapping doesn’t appear to help at all.
I am currently testing a change where users will be able to set some flag on the text object that will results in the disposing of most of the data structures used in the text parsing and layout process.
This will reset the allocations of individual text objects back to those of a newly created text object where it remains in a state where it can still be updated but at the cost of reallocating those buffers.
This should result in significant reduction of the overall memory footprint for those text objects using this new flag.
For instance, a text object that contains 31,718 character ends up allocating a characterInfo[ ] that takes 11.4mb. With the change this same data structure will take 3.0kb.
I will post more detailed information later tonight / over the next few days.
As a quickfix while waiting for the optimization possibility mentioned above, we’ve located a simple change that eliminates the massive TMPro.WordWrapState[ ] allocations.
In TMP_Text.cs, make the ‘m_EllipsisInsertionCandidateStack’ static:
Unfortunately, this does mean that we’ve had to copy the source files of the TMP package into our project as we were otherwise unable to modify the source.
You should already be seeing some improvements in the latest release with regards to WordWrapState, MaterialReference and other data structures used in the parsing and layout of the text.
In the next preview release, there will be additional improvements. This time dealing with the textInfo and sub data structures like characterInfo, etc.
Sounds good. We’ve held off on grabbing the new update because the last time we updated it caused huge problems for us everywhere, but if there are some key fixes in this new version we’ll grab it. We’re currently on 2.1.1, but I see that there’s a “verified” 2.1.3. I assume that’s what you recommend for URP, 2019.4. Thank you!
I finally got back to measuring the fantastic improvement the update brought. With the update, TextMeshProUGUI has shrunk from 33MB down to 8.4MB. And I can’t even find WordWrapState anymore, which used to add 32MB. That’s a GREAT improvement. Nice work!
TMPro.TMP_CharacterInfo is still painfully big–100MB. It sounds like that’s exactly what you’re working on right now, so good luck–we can’t wait! In the meantime, if there’s anything we can do now manually to clear that or reduce it or anything, please let us know.
Hi, @Stephan_B - reviving this thread because I too have been doing some memory profiling and I’m finding that these TMP-related types are building up over time as the user visits various UI screens. Mostly CharacterInfo arrays (8MB) and TMP UI Meshes (2MB).
It feels like these things should go away, for certain objects, once the TMP object is disabled. A flag in “Extras” to clear these things seems like a reasonable idea or maybe the static flag could be used. I need to think about that one.
Also what’s TMP_HighlightState[16]? - there seems to be one for every TMP_Text in the game (300KB), but does that need to be allocated for non-InputField texts?
For now, is there a recommended way to forcefully cause a TMP_Text component to flush it’s cached data?
Sorry to necro this thread, but is there a fix for the TMP_CharacterInfo memory issue coming? We are still getting this as of Unity 2020.3.26f1 and TMP 3.0.6.
Hi, @Stephan_B We’re still looking for a way to force release the TMP_CharacterInfo and other cached data that can be dynamically released when a screen or dialog box is hidden. These things accumulate over time and it doesn’t seem necessary to keep around all this cached data for transient text.
This is something that I am planning on addressing where users will be able to control whether or not the TextInfo and its content which includes the CharacterInfo will be persistent per text label. This should result in a significant memory overhead reduction overall.
I am still working on full support for OpenType Layout features along with support for Color Glyphs (Native Emojis) but once I am out of this OpenType hell, I will be working on text parser and layout improvements which will include the above memory overhead improvements amongst lots of other goodies.
This will be very helpful. Looking forward to that, thanks @Stephan_B !
Wow that Opentype stuff does sound really complicated and probably hellish as well, but very useful for certain language scripts, I can imagine.
One of the TMP layout features you might consider for games is a balanced wrapping for regions where the text is inside of a dynamic (ContentSizeFitter) shape. For example a chat or character dialog bubble. I also do this with popup tutorial text. So let me give you an example line of text:
This is important text as an example of word wrapping.
Now let’s say we can wrap this text onto a second line and we have a maximum width of approximately 8 words (for lack of a RectTransform width here), then we’d get this:
This is important text as an example of word
wrapping.
This doesn’t look so great in a dialog or tutorial bubble, especially if the last word is very short. What would be better is if we say that as long as it’s on two lines, then try to balance the width of those two lines like so:
This is important text as an
example of word wrapping.
I have a custom script that does this where it sees if there’s any wrapping and then it dynamically shrinks the RectTransform width by some step size and then regenerates the text each step until it’s gone onto a third line and then goes back one step. The works, but costs a lot of CPU to regenerate the text mesh so many times. I can send you the script if you’re interested.
Anyway, I just thought this would be a very nice built-in feature to have for games and your version would no doubt be much cheaper to compute than my hacky script.