Instead of repeatedly creating and destroying gameobjects at runtime (bullets for example), you can create a set amount at the start of runtime and call them in the scene when they are needed. When you don't need them, you can then set them inactive in the scene and call on them when needed again. Object Pooling is a great way to optimize your project and lighten your games garbage collection. (Full Object Pooler Script at the end of blog post.)
There are more than a few ways you can implement this. For my current project I decided to have a GameObject called _ObjectPooler and added one script that takes care of all the pooled objects in the scene. This can be altered so you can create a 'Pool Item' class in any other script and call them separately if that's more your style, but for me, at least for the moment, it's simpler to have all the gameobjects being pooled in one location, and calling them in from one location.
I created a script called 'ObjectPooler' and above the class I created a new class called PoolItem.
Next I made the ObjectPooler class a singleton, so it can be easily called from other scripts. (Only one instance of the script is allowed in the game scene).
Just below the 'public static ObjectPooler instance;' line, I created a list from the class PoolItem.
Next, we add the code that will pool our objects. Write the following code after the Start() function.
This will now pool objects into your scene when you play your scene. But we still need to call them to actually use them. Right below the code we just wrote we add a function that will call a pooled gameobject when we want to use it.
This piece of code, when called, will go through each pooled object type we want to call and if one in the list is not active in the scene, then it will return that value/gameobject. Now we have the gameobject we want and can set it active.
In the current project I'm working on, I pooled some 'blood' gameobjects, which are just animated sprite gameobjects. So when I hit an enemy I will grab a blood gameobject from the pool, change its position and set it to active.
When I don't need to show the blood effect anymore, I will call setActive(false) to the blood gameobject, so it can be called again at a later time when needed.
Full ObjectPooler Script
To grab a pooled object (separate script)
When your finished with the object for the moment.