0

Most Unity developers are aware that instantiating and destroying GameObjects repeatedly is something to avoid because it generates some garbage. But a discussion came up about whether it's more efficient to pool regular C# classes (non-GameObject types) that are instantiated and released frequently. It came up in relation to a discussion about an RTS game using the Command Pattern for Unit orders, which is when commands are queued and executed by the units in the game. Over the course of gameplay you can expect that Commands (implementing an ICommand interface) will be created and destroyed a good bit:

unit.Commands.Enqueue( new MoveCommand( goal, MovementSpeed.Fast );

The command gets executed by a CommandProcessor and then when IsFinished or Cancel is true it's set to null and the processor dequeues the next one and runs it.

Is there any benefit to pooling regular C# classes like this in a game? From what I see on Microsoft's documentation, it only recommends pooling objects that are expensive to create and destroy (Unity GameObjects being a prime example). Commands in the game don't consume any native resources (and don't need to implement IDisposable) and they are pretty lightweight, usually just holding a few Vector3 positions, a reference to a Unit or group and a few properties like IsFinished and Cancel.

My position in the debate is that they don't need to be pooled, that the CLR handles all of this just fine and that pooling should be reserved for rapid creation/destruction of GameObjects and anything that consumes native resources, has an expensive initialization and destruction process or generates any type of "garbage" that's left behind. However, I've never really considered this before and I'm not really sure where else to find more in-depth information about the topic. I really just want to know if this is even worth considering/doing and how I can explain to others why it is or isn't.

EDIT: I also think pooling commands and similar things might be less efficient than allowing the CLR to do its thing because we will constantly have more memory than necessary allocated to store the pool in RAM ... any thoughts?

  • 1
    It's debatable. Kidding aside, though, you have to race your horses. I think about how much garbage collection is required by Java games like Minecraft and I can only imagine how much testing they do to settle debates like this. You can't afford to gamble on what others tell you and you can't be so fixated on one solution that in the future you ignore another that might be better. Experiment, test, learn, repeat. – madreflection Nov 24 '21 at 20:15
  • 1
    Totally depends. In your case it doesn't look like those are very memory or performance (regarding creation and destruction) intense types so probably not worth to even think about it, no ;) .. however, if you are going to create and destroy 10.000 of them per frame .. it would have a huge impact and then yes you might consider it – derHugo Nov 24 '21 at 20:40
  • 3
    You should read up on how garbage collection works, in particular the _generational_ aspect of the GC (Gen0 collections are cheap and fast, Gen2, not so much, with Gen1 splitting the difference). If you are creating a ton of small objects, all of which are eligible for collection very soon after, the GC should have no problems. The normal "need to pool objects" recommendation in .NET comes for _Large Objects_ (stored in the large object heap) those are expensive to collect and can slow things down – Flydog57 Nov 24 '21 at 21:22
  • 1
    @Flydog57 yep, you're right about that. They should all be Gen0 objects. They barely take up space in RAM, no native resources, nothing complicated going on. I think pooling commands would be a nightmare, assuming the game might have 250+ units, 10+ types of commands and each Unit may need a pool of 20+ commands of every single type. Sounds like it'd be a big chunk of wasted RAM and add a ton of unnecessary complexity to the code that will make it difficult as hell to maintain and debug. – Aaron Carter Nov 24 '21 at 22:31
  • I'm still researching the subject but most sources are saying only to use pooling where objects are expensive to create and destroy or may consume some native resources that are tricky to deal with. It's generally not recommended to do this in most situations in Unity unless something is rapidly created and destroyed, such as bullets fired by characters. I still think pooling regular C#/.NET objects would add way more complexity to the code base and waste a constant chunk of unneeded RAM to store all these things, for little or no benefit. – Aaron Carter Nov 26 '21 at 00:01

1 Answers1

1

If you're using Unity there's some really good tools in the Unity Profiler that can help you determine if garbage collection is causing performance issues. Its best to check what's slowing your project down the most before increasing complexity with object pooling. Personally I haven't had a situation yet aside from GameObjects that needed to be pooled. Very much a case by case basis.

Sean
  • 11
  • 2