SetActiveRecursively vs Instantiate / Destroy performance

I’ve been tasked with implementing asset pooling in our project, and after my first implementation have found some strange results which I’ve replicated in a test project.

I wrote a test script (at the end of this message) which takes a test object as parameter and then either creates/destroys copies of it every frame, or activates/deactivates the copies (using SetActiveRecursively).

Using a standard cube as my test object, 2000 copies, the profiler shows the following:

Instantiating/Destroying the objects on the left, activating and deactivating on the right. Creating/destroying the objects take about 115ms on the CPU, Activating/Deactivating take about 315ms.

Why does activating and deactivating take more time than creating and destroying the same amount of objects? Using a blank object as test case does not impact the results of the test.

It would be great if someone else could take my script and try to reproduce my findings. If needed I can upload a test project, but it is simple enough using my script below: Create a blank project, add 2 gameobjects to the scene, add the script to one and assign the other object to TestObject, then run and press F7 to create/destroy or F8 to activate/deactivate the copies.

Bonus question: The purple spikes in GPU usage are all due to RenderTexture.SetActive. What could be causing that in an absolutely blank project?

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ActiveTest : MonoBehaviour {

	bool toggleActive = false;
	bool createDestroy = false;
	public GameObject TestObject;
	public int amount = 2000;
	private List<GameObject>  TestObjects;
	
	void Start()
	{
		TestObjects = new List<GameObject>();
	
		for (int i = 0; i < amount; i++)
			TestObjects.Add (Instantiate(TestObject,TestObject.transform.position + (Vector3.right) * i,Quaternion.identity) as GameObject);
	}
	
	void Update () 
	{
		if (Input.GetKeyDown(KeyCode.F8))
		{
			toggleActive = !toggleActive;
			if (toggleActive)
				createDestroy = false;
				
				
			if (!createDestroy  TestObjects.Count == 0)
			{
				for (int i = 0; i < amount; i++)
					TestObjects.Add (Instantiate(TestObject,TestObject.transform.position + (Vector3.right) * i,Quaternion.identity) as GameObject);
			}
		}
		
		
		if (Input.GetKeyDown(KeyCode.F7))
		{
			createDestroy = !createDestroy;
			if (createDestroy)
				toggleActive = false;
			else
			{
				if (TestObjects.Count == 0)
				{
					for (int i = 0; i < amount; i++)
						TestObjects.Add (Instantiate(TestObject,TestObject.transform.position + (Vector3.right) * i,Quaternion.identity) as GameObject);
				}
			}
		}
		if (toggleActive)
		{
			
			TestObject.SetActiveRecursively(!TestObject.active);
			foreach (var TO in TestObjects)
				TO.SetActiveRecursively(TestObject.active);
		}
		else if (createDestroy)
		{
			if (TestObjects.Count == 0)
			{
				for (int i = 0; i < amount; i++)
					TestObjects.Add (Instantiate(TestObject,TestObject.transform.position + (Vector3.right) * i,Quaternion.identity) as GameObject);
			}
			else
			{
				foreach (var to in TestObjects.ToArray())
				{
					TestObjects.Remove(to);
					Destroy(to.gameObject);
				}
			}
		}
	}
}

The point of new SetActive system is to call it once for all the 2000 objects, it now affects hierarchy thus its slower than before.
But you can’t call it 2000 times at once and expect it to be fast.

I probably should have mentioned that I am on Unity 3.5.6f4

Using object.active = true/false instead of SetActiveRecursively makes no difference to the performance (which makes sense considering that my test object has no child objects to begin with).

I’m not expecting it to be fast with 2000 objects, I am just expecting it to be faster than actually instantiating and destroying the objects! Using fewer objects in an active game scene still has an impact on framerate.

In Unity 4, SetActive (which is equivalent to SetActiveRecursively in 3.x) seems to be a bit faster than Instantiate, but it’s still pretty slow. I tried to do the same thing (implemenmt an object pool) and came across the same issue. Obviously you could leave all your items active and just hide them away somewhere, but then you’d have 2000 objects (or however many) processing the whole time. I’d like to hear a good solution to this, but suspect there isn’t one.

I haven’t really come across a better solution, but I have found that performance in the editor when it comes to creating/activating is not indicative at all of how performance will be in a build. Also, we were doing a lot of effects manually, that we’ve now reworked into using standard particle effects which has had a great impact on performance. In any case though, pooling and activating/deactivating is still more efficient than create/destroying.

Good to know about performance in build vs editor, thanks. I’d only been testing this in the editor, and I really need to do more testing on the built version.