8
\$\begingroup\$

In Unity, should we avoid string literals in frequently executed methods (like Update()) to avoid unnecessary memory allocations and instead store string values into fields?

class TouchInputManager : MonoBehaviour
{
    // private const string messageVar = "OnFingerMove";
    /* ... */
    private void HandleFingerMove(Finger finger)
    {
        /* ... */
        gameObj.SendMessage("OnFingerMove");
        // vs.
        // gameObj.SendMessage(messageVar);
    }
}

I assume that the string literal "OnFingerMove" will allocate new memory on every frame. Will the compiler somehow optimize string literals to reduce garbage? I read some articles that suggest avoiding string concatenation in methods executed on every frame, so I started wondering if string literals would also create garbage in the heap.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ This is input handling code, isn't it? How often do your really receive input events? Maybe one every couple frames? When a piece of code doesn't get executed a couple thousand times per frame, then such low-level performance optimization concerns are usually not worth thinking about. Well, maybe this question is interesting from an academic perspective, but in general you should direct your optimization efforts to code that is actually performance-critical. The Profiler can help you to detect such code. \$\endgroup\$
    – Philipp
    Mar 25 at 10:00
  • \$\begingroup\$ @Philipp My global FingerMove event handler will most often call move handlers for the Movement and Aim joysticks. It's a mobile MOBA game. I expect the Movement and Aim joysticks to be moved every single frame. I started optimizing my code and removing statements that create objects of reference types from methods that execute on every frame. AFAIK its enough for several statements that allocate memory to execute once every frame to create GC problems, not thousand times per frame. People suggest avoiding string concatenations even if they are executed only once per frame. Thanks for answerin \$\endgroup\$ Mar 25 at 10:13
  • \$\begingroup\$ Relatedly: I have wondered sometimes if I should implement a string caching system for things like numeric readouts which might be frequently updating and reusing the same numbers. I don't know whether .Net's string formatting or TextMeshPro have any built-in optimizations for this use case that I'd be duplicating. \$\endgroup\$
    – DMGregory
    Mar 25 at 12:26
  • 7
    \$\begingroup\$ It's funny you're worried about strings, since I'm pretty sure SendMessage is already a less-efficient shortcut since it has to check who wants the message. The more programmery way is to figure out who wants to know and directly tell them. But SendMessage was written for a reason -- it's easy and fast enough most of the time. \$\endgroup\$ Mar 25 at 18:31
  • 1
    \$\begingroup\$ @OwenReynolds Such patterns are used primarily because they reduce unecessary static coupling between modules / classes, not necessarily because they're "easy". \$\endgroup\$
    – Engineer
    Mar 26 at 17:46

2 Answers 2

24
\$\begingroup\$

A string literal in C# will be compiled to string literals in IL.

Then the IL is compiled to machine (or to C++ and then to machine code if you are using IL2CPP).

On machine code the strings constants should be placed on a data section and referenced where needed. Note: it is not a requirement of the .NET standard that the string literals will be handled this way, but this is what happens in practice.

To be clear: you do not need to intern constants.

Thus, using a string literal does not cause additional allocations. From a performance standpoint using a named constant or a literal should make no difference.

It would only make a difference from a maintanability standpoint, if you use the same string literal in multiple places, creating a named constant allows you to change it in a single place (i.e. a single source of truth).

\$\endgroup\$
2
  • \$\begingroup\$ Also, when it comes to maintainability, EVENT_IDENTIFIER is a lot better than "OnFingerMove". In other words, if you name things properly, the result will be more readable in the future... \$\endgroup\$
    – Jasper
    Mar 26 at 8:55
  • 7
    \$\begingroup\$ Just as important, if you make a typo when typing EVENT_IDENTIFIER, you'll get a compile-time error and fix it within 30 seconds. OTOH if you make a typo when typing "OnFingerMove", it will compile just fine and you'll waste 30 minutes trying to figure out why your program isn't handling the events properly at runtime. \$\endgroup\$ Mar 26 at 23:20
5
\$\begingroup\$

There is a trick with strings called "interning" Which stores the string in a global pool and lets you get the same string object for the same string contents.

C# is defined to automatically intern all string literals:

The intern pool conserves string storage. If you assign a literal string constant to several variables, each variable is set to reference the same constant in the intern pool instead of referencing several different instances of String that have identical values.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ that being said... Using string literals should be avoided much like magic numbers should be avoided because it makes more sense to modify a single constant than a thousand a thousand instances where that string constant was used. TLDR: this is true, but it is bad practice. \$\endgroup\$
    – Questor
    Mar 25 at 18:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .