I should of mentioned before that if you pool objects and operate on them properly even if they are on the heap they won’t create collectable garbage either.
The gc is fast but when it actually needs to perform a collection your game is on pause until it is done.
Typically what i see on windows is when about 1.5 to 2 mb of collectable or unreachable memory add up. The gc will do a collect.
The more it has to call collect the more it will pause. The more it pauses the more chance that you will notice it as a slight stutter skipping or apparent slow down.
For example the following seems like a simple question but the answer isn’t straight forward.
How do you draw a variable that changes every frame without triggering garbage collections?
Here i just ToString() a bunch of numbers to see a quick positional graph to debug buttons i was working on and bam 50 collects per second and a huge frame drop… So you might say well of course a list is a heap object as is stringbuilder. But the normal frame rate counter here is too and it causes no collections. In this picture i didn’t care the lines were going to get deleted which is why i generated them locally in the method and they made a ton of trash that generated a ton of collections.
Point im trying to make is how much garbage getting collected is relative. One line can be too much or worse you can just do a little here and there till it all adds up to be to much. If you aren’t watching it then it’s gonna start adding up.
Anyways the question itself should be directly answered…
I see a lot of MonoGame/XNA tutorials that do things like:
Create a new Vector2(…) in Draw
Create a new Rect(…) in Draw
etc.
These are value types because structs are value types.
It’s value is copied when its value reference variable is, passed by value into a method parameter.
This does not mean it is on the stack or on the heap.
Is it actually a bad idea to do this?
Considering that draw/update
run at 30-60fps, you’re creating (let’s say, per sprite/entity) 30-60
instances per second, and these will eventually get garbage-collected,
won’t they?
As you have stated the question …
It depends on the context or scope of the type instance.
(by scope i mean the lifetime of the variable in the code { block } you are considering).
If the vector2 is declared in the game1 class or a pretty much any method as a temporary variable, since the compiler can known that game1 will exist for the lifetime of the application and its pass by value. As well the compiler can know exactly how long the temp variable will last. (provided there is no yield or something weird)
Then it can put it on the stack.
…
If the vector2 is a variable of game1 is said to be local to a instance of game1, it is one of game1’s method variables. There is no garbage reassigning it in game1’s update or draw. (unless you do something really weird to it).
If the vector2 is in a different class object and you create a instance of that object in a local Game1 method for example Update or Draw, That struct is then on the heap with the reference type object instance. When the method exits that instance including the vector2 inside it will be out of walkable scope to the application and will be marked for collection at some time by the gc.
Or am I missing something? I'm going through some length to "cache"
these things inside persistent properties that only update when the
underlying data changes, but is this a micro-optimization?
Cache if you need to.
If you can use structs go ahead if you don’t want to fine you can use class instances.
If either are on the heap and they go out of scope to game1 however then they’ll be garbage collected at some point.
All calls to new create garbage that has nothing to do with a actual Collection being triggered.
(Garbage isn’t evil garbage is memory)
Your reference type instances or structs on the heap going out of application scope creates a collection random number 90% of the time.
(Which for a game at a fast paced critical action packed moment… is evil).
Ditto for Color instances.
Same as above.
There are a couple other ways structs can end up on the heap as well. TLDR already.’
Here is a good article.