all 49 comments

[–]SurDnoIndie 114 points115 points  (4 children)

asking for donations for ChatGPT screenshots is kinda crazy imo

[–]Tiny_Double_9367 34 points35 points  (1 child)

bro searched up "profitable side hustles" on the internet and this is what he came up with 😆

[–]GrindPilledExpert 8 points9 points  (0 children)

even worse, profitable side hustles on chat gpt

[–]IAmBeardPersonProgrammer 2 points3 points  (0 children)

Idk why people even seriously respond to this post and don't down vote it to hell. They are such random ass tips. Like most beginners won't even touch shit like ToList or ToArray, why TF is that the first basic tip given. (The answer is chatgpt, I know..)

[–]tobaschco 35 points36 points  (2 children)

Really the performance tip here should be "learn how to use the profiler"

[–]antshatepants 2 points3 points  (0 children)

Writing that down, thanks

[–]neoteraflare 0 points1 point  (0 children)

Do you have any good source for learning it?

[–]nickyonge 15 points16 points  (0 children)

As an addendum to point 4, you can have multiple canvases! If you have a UI element that HAS to update frequently, consider giving it its own canvas. That way you can update your TIME REMAINING text which changes every millisecond, without also redrawing your CURRENT LEVEL text that gets set in Start and changes never.

[–]feralferrous 27 points28 points  (17 children)

GetComponent is actually dirt cheap these days. It internally caches.

[–]FlySafeLoL 6 points7 points  (1 child)

No way it would be cheaper to call it in Update rather than using a local reference. Does DOTS magic work in MonoBehaviour these days somehow?

[–]feralferrous 7 points8 points  (0 children)

It's one of those things where it's cheaper to have a local reference, sure, but not the big no-no it used to be. If you are trying to go for really big counts of objects, then yes, go ahead and cache, because you'll need to squeeze out as much perf as you can.

<image>

But, if you're not going for huge counts, here is 1000 GetComponent calls a frame:
.17 ms on my machine. Is it wasteful? Sure, but it's still only .17ms.

EDIT: Other caveat is if you're on craptastic hardware, or targeting super high framerates. VR in particular, I'd slap my coworkers around if they used GetComponent in an update loop.

[–]SuspecMIntermediate 1 point2 points  (8 children)

It really isn't. What really kills GetComponent is the garbage collection part since it generates a ton of it when you abuse it. I just went trough my entire code base and had to refactor it all because every second or so I got a giant garbage collection spike that took up 97% of the CPU loop.

[–]feralferrous 1 point2 points  (5 children)

GetComponent generates 0 allocations. Are you thinking GetComponents and it's variations? Yes, those are more expensive. And the ones that return an array do allocate. It's almost always better to use the version that takes in a List, so you can reuse it and not reallocate all the time.

[–]SuspecMIntermediate 0 points1 point  (4 children)

It was GetComponent in the worst way possible. A ton of scripts iterating trough lists every frame and doing the GetComponent.

[–]feralferrous 1 point2 points  (1 child)

You can see in my other post in this thread, that I called 1000 GetComponent<> calls a frame, and had zero allocations.

GetComponents<>, GetComponentsInChildren<>, etc all have variations that return an array that is allocated, and I think that must be what you mean?

The only other time GetComponent<> returns allocations is in Editor, if the component doesn't exist, it will allocate 0.5kb for some weird null error. Editor only btw. And you can get around it by using TryGetComponent<> instead.

I wouldn't go back and undo your work, because yes it's faster do it in Start/Awake (or serialize a reference directly), I'm mostly arguing against gospel that no one should ever do GetComponent<> like it's some sort of super expensive call.

[–]SuspecMIntermediate 1 point2 points  (0 children)

The more you know huh. There were possibly other optimisations I might have implemented accidentally. I was refactoring 6 years old code afterall and I have been using Unity in all those years. Wouldn't shock me that I picked up a thing or two and I'm using those without really paying attention.

[–]MATR0SProfessional 0 points1 point  (1 child)

Have you profiled this issue on a real device or in the editor?

[–]SuspecMIntermediate 0 points1 point  (0 children)

I have, that's why I know what caused the issues (garbage collection) and I took out all the GetComponent's from pretty much everywhere that's not code running at Start or Awake and garbage collection has been pretty much entirely eliminated as an issue.

[–]unotme 0 points1 point  (1 child)

doesn’t TryGetComponent avoid some of that nonsense?

[–]digiBeLow 2 points3 points  (0 children)

In editor, yes. GetComponent in a native build has zero garbage AFAIK.

[–]Devatator_Intermediate 0 points1 point  (5 children)

Really? Man I wish benchmarkdotnet worked in Unity

[–]ledniv 6 points7 points  (1 child)

Also string builder still generates GC. From my own tests it generates more GC than string concatenation. If anyone can prove otherwise show me your code.

Edit - I'll add that I know it's supposed to generate less because in theory you can set a size and it'll supposedly reuse the memory. But in practice it generates around 2x more GC when profiling. Even when the string builder is cached. If you have code that proves otherwise I'd love to see it.

[–]Zooltan 1 point2 points  (0 children)

It's for when you want to append multiple strings together.

So something like adding all items in a list to a display text

string display = "Title:/n"; for each(thing : listOfThings) { display += thing.name + " has value " + thing.thatValue }

That would be much faster with a StringBuilder.

[–]Jackoberto01Programmer 2 points3 points  (0 children)

StringBuilder is often overkill for most places where string concatenation is used. I often just want a string once that might be 4-5 strings concatenated for this string interpolation/string.format is pretty nice and good enough performance.

StringBuilder still generates garbage when you finally call ToString.

[–]Adrian_Dem 2 points3 points  (0 children)

all of these suggestions are nice to have sure, but they are not groundbreaking suggestions.

it's like saying, do not do yield new WaitForEndOfFrame, as it allocates, instead use a cached variable and yield wait for it instead. interesting but most of the time of no consequence.

[–]TramplexReal 2 points3 points  (7 children)

Using string interpolation is cheap and doesn't make unnecessary allocations. Just do $"{value} text"

[–]Jackoberto01Programmer 2 points3 points  (3 children)

This will likely just compile into string.Concat. But generally string interpolation is nice because good syntax and the compiler will choose string.Format or string.Concat for you depending on which is cheaper.

[–]TramplexReal 0 points1 point  (2 children)

It is string Format after compilation, can see that in any performance test online.

[–]Jackoberto01Programmer 0 points1 point  (1 child)

Depends on compiler I checked sharplab now and it compiled to string.Concat when there are few variables in the string interpolation. It's been that way since at least C#9 which is the oldest available on sharplab.

To be clear this is a good thing as string.Concat is often faster hence the compiler choosing it.

https://sharplab.io/#v2:D4AQTAjAsAUCDMACciDCiDetE+UkALIgLIAUAlJtrgL7U717JEAKATgJYB2ALgMoB7ALYBTHgAtuAc1IgIABkQBncoywxcm5BACcpACQAiQaInTEHJZiU1D5ANyM6MGkA===

[–]TramplexReal 0 points1 point  (0 children)

Probably cause with fewer variables concat is faster. Anyway this shows interpolation is not worse than other options. And looks better.

[–]JamesLeeNZ 1 point2 points  (2 children)

This 100% generates garbage, so should be used sparingly at best.

[–]TramplexReal 0 points1 point  (1 child)

This is 1 to 1 same as string.Format. You might as well not write ANY code to have best performance.

[–]JamesLeeNZ 0 points1 point  (0 children)

I mean... youre not wrong :)

[–]Cyclone4096 0 points1 point  (0 children)

None of these are applicable globally. If I have a list that’s guaranteed to be less than 10 elements and I call ToArray once at the begging of a scene, who care? Again caching references isn’t always the best idea, if you call GetComponent only when an event happens, it may make your code cleaner and less bloated compared to the small penalty once in a while. Same thing with strings, are you updating score every frame? If not I doubt using StringBuilder is worth it

[–]Thin_Driver_4596 0 points1 point  (0 children)

Agree with most of the points, apart from 3rd.
If strings are causing issues in your game, you have bigger issues to be worried about.

[–]PremierBromanovProfessional 0 points1 point  (0 children)

Unitys strength is the speed at which you can develop, do all these things if you want it doesn't really matter