Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Noxury · Apr 01, 2017 at 06:16 PM · textstringgarbage-collection

How to avoid garbage for strings?

I call this line every frame, but it allocs 1.1kb everytime. This makes in 1 second (assuming 60fps) 66kb and therefore ~4mb per minute. I don't know how to avoid this garbaging since it needs to update every frame.

 text_height.text = ((int)player.transform.position.y).ToString("000") + "m"; //GC 1.1kb per frame
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

6 Replies

· Add your reply
  • Sort: 
avatar image
3
Best Answer

Answer by Bunny83 · Apr 01, 2017 at 07:40 PM

Strings are immutable objects in C# / .NET. There are ways (using unsafe code) to directly manipulating the memory of a string object. One example is the gstring library written by @vexe. However it's not really recommended to do this.

There are two ways how you can improve your specific case:

  • First, don't concat several strings. You can use string.Format.

  • Second, don't update it every frame. Since you cast the position into an int, the value might not change every frame. You can use a second cached int value to check if the number has changed.

Example:

 private int oldVal = int.MaxValue;
 
 void Update()
 {
     int val = (int)player.transform.position.y;
     if (val != oldVal)
     {
         oldVal = val;
         text_height.text = string.Format("{0:D2}m", val);
     }
 }

This will only create a new string when the value has changed and it will only create "one" string. .

Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Oct 03, 2020 at 11:39 PM 0
Share

Since the question got already bumped I'd like to add that besides the string that is allocated we also will allocate a "box" for the "val" parameter because string.Format takes parameters of type object, so the int value need to be "boxed". However that's a tiny amount of memory. Though that was the main motivation for vexe to create the gstring library to get rid of most of those tiny allocations.


Apart from the the obvious memory allocations we just talked about, there might be additional allocations behind the scenes. For example when you set / change the text of an UI text component like we did here, the UI canvas has to update / reconstruct the mesh that represents the text in the scene. This might result in additional memory allocations.

avatar image JDelekto · Nov 08, 2020 at 01:10 AM 0
Share

@Bunny83 are there any drawbacks to using a StringBuilder which has had a reasonable buffer size pre-allocated through the use of one of the overloaded constructors?

avatar image Chris-Trueman JDelekto · Nov 08, 2020 at 01:54 AM 0
Share

StringBuilder is good for composing larger strings to prevent multiple allocations, the drawback is that calling ToString() on it creates a new string every time it is called. I heard that it isn't supposed to in the newer versions of .NET but it does in Unity. If you are using T$$anonymous$$P it will take a StringBuilder in one of the overrides for SetText(). That will get the underlying char array and use that to render the text, avoiding the allocation of ToString().

You can replace StringBuilder with string interpolation and get the same allocations when composing a string. Using StringBuilder.AppendFormat() will generate garbage when it uses ToString() on the type it is formatting, so if you want formatting you will generate garbage for each value you format.

I have a project somewhere that tested the difference between StringBuilder and string interpolation and found that both allocated the same or sometimes less with string interpolation.

avatar image JDelekto Chris-Trueman · Nov 08, 2020 at 02:36 AM 0
Share

I looked at the generated IL from string interpolation and it is basically syntactic sugar for String.Format() which will return a new string.

It seems like the happy medium would be with a pre-allocated StringBuilder using AppendFormat(), avoiding the use of ToString(), and passing the StringBuilder to methods that can work with the internal buffer directly (which I imagine is through the Chars[] array).

Show more comments
avatar image
0

Answer by AnKOu · Dec 04, 2019 at 09:37 AM

You should cache each "{0:D2}m", "000" , "m" into member variable.

 private const string m_format = "{0:D2}m";
 private const string m_value = "000";
 private const string m_m = "m";

Otherwise, it will instantiate a new string each time.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Chris-Trueman · Apr 14, 2020 at 07:51 AM 5
Share

This is false. Any string literal, meaning anything between quotes will be cached by the system already so there is no need to do this redundantly.

avatar image
-1

Answer by Monsoonexe · Oct 03, 2020 at 07:23 PM

The garbage generation is also coming from 'player.transform'. MonoBehaviour.transform is a Property, which means it is actually a function. It is secretly calling GetComponent() every frame, which is a heavy operation since it uses reflection and generates garbage. Consider caching it.

 public class MyMono : MonoBehaviour
 {
     private Transform myTransform;
 
    private void Start()
     {
         myTransform = transform;
     }
 
 }
 
Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Hellium · Oct 03, 2020 at 08:41 PM 1
Share

I don't think calling the transform getter generates garbage, nor calls GetComponent. The transform is cached in the native code side AFAIK

https://forum.unity.com/threads/cache-transform-really-needed.356875/

(it's still more performant to cache it on the C# side)

avatar image Bunny83 Hellium · Oct 03, 2020 at 11:31 PM 1
Share

Right, this answer is just as misleading as AnKOu's answer. People should be more careful with ter$$anonymous$$ology and generalisation. Yes, transform is a property and calls a native code method. This fact alone does not imply any memory allocations. On the other hand the "name" property of a gameobject will actually allocate a new string every time it's read. GetComponent isn't as bad as some people claim. GetComponent could allocate memory, but only when testing inside the editor and only when the component you're looking for does not exist (which is never the case for the transform component).


Reflection is a quite large system and most functions of the reflection system do not allocate any memory at all. Reflection mainly has issues with value types as they need to be boxed. Apart from that GetComponent doesn't use reflection since GetComponent finds the references on the native side. The reflection system is part of the managed runtime.

avatar image Chris-Trueman · Oct 03, 2020 at 10:03 PM 1
Share

I can confirm this is not needed. I run the profiler quite often to see if methods generate garbage and this doesn't show up as generating any garbage, It also takes a total of 0.00ms. If it is in your project and it's using Unity 5.0 and up, I would file a bug report.

avatar image
0

Answer by florinel2102 · Nov 07, 2020 at 02:19 PM

You could use StringBuilder Class from System.Text and also instead of creating a new instance every frame , you could use StringBuilder.Clear() . For more information about fixing memory performance

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by andrew-lukasik · Nov 07, 2020 at 05:29 PM

Lookup table

and say goodbye to these pesky allocations forever. I expand on this simple & practical solution a bit more in my CacheStrings repo but here is the essence of it:

 Transform player;
 UnityEngine.UI.Text text_height;
 Dictionary<int,string> _lookup = new Dictionary<int,string>(100);
 readonly System.Func<int,string> _keyToString = (i) => $"{i:000}m";
 void Awake ()
 {
     // warm it up for range you expect in-game:
     for( int i=0 ; i<100 ; i++ )
         _lookup.Add( i , _keyToString(i) );
 }
 void Update ()
 {
     string text;
     {
         int key = (int) player.position.y;
         if( !_lookup.TryGetValue( key , out text ) )// returns reference to existing allocation
         {
             text = _keyToString(key);// allocates string missing from the pool
             _lookup.Add( key , text );
         }
     }
 
     text_height.text = text;
 }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

75 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Unity UI: Text Adventure 2 Answers

Display numbers in UI.Text Garbage Free? 2 Answers

X.Text just uses random values 1 Answer

Changing a text equal to a string variable 1 Answer

Problem with makeing text appear on screen 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges