[測試] Unity Instantiate 與 SetAcive 的效能差異? - Unity Instantiate v.s. SetAcive?

一個沒有深入結論的小測試,所以標題是問號。先直接給結果:

1492069298795
1492071078733

  • 測試版本:Unity 5.5.0f3,PC Editor 環境
  • 測試的物件:Unity 內建的 Sphere
  • 測試的數量:300 * 300 (即 90000 個)

詳細過程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameObjectLoadTest : MonoBehaviour {
public GameObject TestPrefab;
public int TestAmountX = 100;
public int TestAmountY = 100;
public float ObjectGrid = 1f;
public Vector3 Moving = new Vector3 (10, 10, 10);
private List<GameObject> m_gameObjectList = new List<GameObject>();

void Start () {
float timer;
timer = Time.realtimeSinceStartup;
InstantiatePrefab ();
Debug.Log (string.Format ("InstantiatePrefab: {0}", Time.realtimeSinceStartup - timer));

timer = Time.realtimeSinceStartup;SetIntoGrid ();
Debug.Log (string.Format ("SetIntoGrid: {0}", Time.realtimeSinceStartup - timer));

timer = Time.realtimeSinceStartup;
SetAllActive (false);
Debug.Log (string.Format ("SetAllActive(false): {0}", Time.realtimeSinceStartup - timer));

timer = Time.realtimeSinceStartup;
SetAllActive (true);
Debug.Log (string.Format ("SetAllActive(true): {0}", Time.realtimeSinceStartup - timer));

timer = Time.realtimeSinceStartup;
MovingAll ();
Debug.Log (string.Format ("MovingAll: {0}", Time.realtimeSinceStartup - timer));
}
private void InstantiatePrefab () {
for (int x = 0; x < TestAmountX; x++) {
for (int y = 0; y < TestAmountY; y++) {
m_gameObjectList.Add(GameObject.Instantiate<GameObject> (TestPrefab, this.transform));
}
}
}
private void SetIntoGrid () {
for (int x = 0; x < TestAmountX; x++) {
for (int y = 0; y < TestAmountY; y++) {
m_gameObjectList[x * TestAmountY + y].transform.localPosition = new Vector2(x * ObjectGrid, y * ObjectGrid);
}
}
}
private void SetAllActive (bool active) {
for (int x = 0; x < TestAmountX; x++) {
for (int y = 0; y < TestAmountY; y++) {
m_gameObjectList[x * TestAmountY + y].gameObject.SetActive(active);
}
}
}
private void MovingAll () {
for (int x = 0; x < TestAmountX; x++) {
for (int y = 0; y < TestAmountY; y++) {
Vector3 newPos = m_gameObjectList[x * TestAmountX + y].transform.localPosition + Moving;
m_gameObjectList[x * TestAmountY + y].transform.localPosition = newPos;
}
}
}
}

沒有結論的說明

一般來說,提到物件的隱藏,會有三個效能不同的手段:

  • 銷毀物件,需要時再建立
  • 關閉物件,需要時再啟動 (SetActive)
  • 移到鏡頭外

依照隱藏與顯示的切換頻率,以及硬體狀況,會針對不同物件採用不同的手段。

這次測試單純只是想知道運算效能上的差異比例,然後這次的測試結果:

1492069298795

很明顯,GameObject.Instantiate 創建物件最耗效能,SetActive 相對節省效能一點,移動物件則最節省效能。

不過三個方法中,物件是否在場景中,Component 是否運作中等因素,對於 CPU、GPU、記憶體所產生的負擔也各自不同,所以並不能單就這筆數據決定三種方法的優劣,一切還是要因事制宜為主。

不過 SetActive 一關一開的效能消耗比我想像中高,然後關閉物件比開啟物件更耗效能?真神秘啊 …

追加測試

1492071078733

這次測試總共進行了兩次物件的關閉與開啟 (SetActive),並加上 Destory 的測試。

結果第二輪的物件關閉就不再大幅消耗效能了?真是太神奇了 … 不知道隔了一段時間之後再關閉物件又是如何? 然後同為移動物件,物件之間的相對位置似乎也會影響效能? 感覺這個測試流程建立的太簡陋,這些測試都是在 Start 中一次完成,所以沒有進到畫面 render 的階段,也沒有把一些不定因素排除,所以這個結果僅供參考,跟實際遊戲運作時的狀況可能有落差。

** 額外的結論:從測試中可以看出來,SetActive 的相關工作基本上都是在行內直接進行,所以在一個 Update 之中因為邏輯判斷對一個物件重複開開關關,會有無謂的效能消耗。(雖然我知道,有時候這樣很方便)