Mono的托管內(nèi)存的優(yōu)化主要是代碼的優(yōu)化,以下部分是我在網(wǎng)上收集的資料:
1.盡量不要動態(tài)的Instantiate和Destroy Object,使用Object Pool??纯次抑皩懙囊黄恼戮突径耍?/p>
2.盡量不要再Update函數(shù)中做復雜計算,如有需要,可以隔N幀計算一次。
3.不要動態(tài)的產(chǎn)生字符串,如Debug.Log("boo" + "hoo"),盡量預先創(chuàng)建好這些字符串資源。
4.Cache一些東西,在update里面盡量避免search,如GameObject.FindWithTag("")、GetComponent這樣的調用,可以在Start中預先存起來。
5.盡量減少函數(shù)調用棧,用x = (x > 0 ? x : -x);代替x = Mathf.Abs(x)
6.下面的代碼是幾個GC“噩夢”。
String的相加操作,會頻繁申請內(nèi)存并釋放,導致gc頻繁,使用System.Text.StringBuilder代替
- <span style="font-family:Comic Sans MS;">function ConcatExample(intArray: int[]) {
-
- var line = intArray[0].ToString();
- for (i = 1; i < intArray.Length; i++) {
- line += ", " + intArray[i].ToString();
-
- }
- return line;
- }</span>
7.在函數(shù)中動態(tài)new array,最好將一個array、傳進函數(shù)里修改
- <span style="font-family:Comic Sans MS;">function RandomList(numElements: int) {
-
- var result = new float[numElements];
- for (i = 0; i < numElements; i++) {
- result[i] = Random.value;
- }
- return result;
- }</span>
8.function Update() { DoSomeThing(); }
可改為每5幀處理一次:
- <span style="font-family:Comic Sans MS;">function Update() { if(Time.frameCount % 5 == 0) { DoSomeThing(); } }</span>
9.定時重復處理用 InvokeRepeating 函數(shù)實現(xiàn)
比如,啟動0.5秒后每隔1秒執(zhí)行一次 DoSomeThing 函數(shù):
- <span style="font-family:Comic Sans MS;">function Start() { InvokeRepeating("DoSomeThing", 0.5, 1.0); }</span>
10. 優(yōu)化 Update, FixedUpdate, LateUpdate 等每幀處理的函數(shù)
函數(shù)里面的變量盡量在頭部聲明。比如:
- <span style="font-family:Comic Sans MS;">function Update() { var pos: Vector3 = transform.position; }</span>
可改為
- <span style="font-family:Comic Sans MS;">private var pos: Vector3; function Update(){ pos = transform.position; }</span>
11.主動回收垃圾,給某個 GameObject 綁上以下的代碼:
function Update() { if(Time.frameCount % 50 == 0) { System.GC.Collect(); } }
12.優(yōu)化數(shù)學計算,比如:如果可以避免使用浮點型(float),盡量使用整形(int),盡量少用復雜的數(shù)學函數(shù)比如 Sin 和 Cos 等等。
13.,減少固定增量時間,將固定增量時間值設定在0.04-0.067區(qū)間(即,每秒15-25幀)。您可以通過Edit->Project Settings->Time來改變這個值。這樣做降低了FixedUpdate函數(shù)被調用的頻率以及物理引擎執(zhí)行碰撞檢測與剛體更新的頻率。如果您使用了較低的固定增量時間,并且在主角身上使用了剛體部件,那么您可以啟用插值辦法來平滑剛體組件。
14.減少GetComponent的調用,使用 GetComponent或內(nèi)置組件訪問器會產(chǎn)生明顯的開銷。您可以通過一次獲取組件的引用來避免開銷,并將該引用分配給一個變量(有時稱為"緩存"的引用)。例如,如果您使用如下的代碼:
- <span style="font-family:Comic Sans MS;">function Update () {
- transform.Translate(0, 1, 0);
- }</span>
通過下面的更改您將獲得更好的性能:
- <span style="font-family:Comic Sans MS;">var myTransform : Transform;
- function Awake () {
- myTransform = transform;}
- function Update () {
- myTransform.Translate(0, 1, 0);
- }</span>
15.避免分配內(nèi)存,您應該避免分配新對象,除非你真的需要,因為他們不再在使用時,會增加垃圾回收系統(tǒng)的開銷。您可以經(jīng)常重復使用數(shù)組和其他對象,而不是分配新的數(shù)組或對象。這樣做好處則是盡量減少垃圾的回收工作。同時,在某些可能的情況下,您也可以使用結構(struct)來代替類(class)。這是因為,結構變量主要存放在棧區(qū)而非堆區(qū)。因為棧的分配較快,并且不調用垃圾回收操作,所以當結構變量比較小時可以提升程序的運行性能。但是當結構體較大時,雖然它仍可避免分配/回收的開銷,而它由于"傳值"操作也會導致單獨的開銷,實際上它可能比等效對象類的效率還要低。
16.使用內(nèi)置數(shù)組,內(nèi)置數(shù)組是非??斓摹rrayList或Array類很容易使用,你能輕易添加元件。但是他們有完全不同的速度。 內(nèi)置數(shù)組有固定長度,并且大多時候你會事先知道最大長度然后填充它。內(nèi)置數(shù)組最好的一點是他們直接嵌入結構數(shù)據(jù)類型在一個緊密的緩存里,而不需要任何額外 類型信息或其他開銷。因此,在緩存中遍歷它是非常容易的,因為每個元素都是對齊的。
- private var positions : Vector3[];function Awake () { positions = new Vector3[100]; for (var i=0;i<100;i++) positions[i] = Vector3.zero;}
17.使用靜態(tài)類型
當使用JavaScript很重要的優(yōu)化是使用靜態(tài)類型替代動態(tài)類型。Unity使用一種技術叫做類型推理的技術來自動轉換javascript為靜態(tài)類型腳本。
var foo = 5;
上面例子中的foo將自動被推斷為一個整數(shù)值。因此,Unity可能使用大量的編輯時間進行優(yōu)化,而不使用耗時的動態(tài)名稱變量查找等。這就是為什么Unity的JavaScript執(zhí)行平均速度是其他JavaScript的20倍的原因之一。
唯一的問題是有時不是所有的東西都能做類型推斷,Unity將會為這些變量重新使用動態(tài)類型。通過這樣,編寫JavaScript代碼很簡單,但也會使代碼運行速度變慢。
看個例子:
- function Start ()
- {
- var foo = GetComponent(MyScript);
- foo.DoSomething();
- }
這里foo將是動態(tài)類型,因此呼叫函數(shù)DoSomething必須要較長的時間,因為foo的類型未知,它必須弄明白是否支持DoSomething函數(shù),如果支持,調用函數(shù)。
- function Start ()
- {
- var foo : MyScript = GetComponent(MyScript);
- foo.DoSomething();
- }
這里我們強制foo為指定類型,你將獲得更好的性能。
18.使用#pragma strict
現(xiàn) 在問題是,你通常不會意識到你在使用動態(tài)類型。#pragma strict可以解決這個問題!簡單的添加#pragma strict在腳本頂部,之后Unity將禁用腳本的動態(tài)類型,強制你使用靜態(tài)類型。如果有一個類型未知,Unity將報告編譯錯誤。下面,foo將在編 譯時報錯:
- #pragma strict
- function Start ()
- {
- var foo = GetComponent(MyScript);
- foo.DoSomething();
- }
19.緩存組件查找
另一個優(yōu)化是組件緩存。這種優(yōu)化需要一些代碼并且不是總有必要。但是如果你的代碼真的很大,并且你需要盡可能的性能提升,它會是很好的優(yōu)化。
當你通過GetComponent獲取一個組件或一個變量時,Unity必須從游戲物體里找到正確的組件。這時你便能通過一個緩存組件引用到一個私有變量。
將:
- function Update () {
- transform.Translate(0, 0, 5);
- }
-
- //轉換為:
-
- private var myTransform : Transform;
- function Awake () {
- myTransform = transform;
- }
- function Update () {
- myTransform.Translate(0, 0, 5);
- }
后面的代碼運行較快,因為Unity不用在每一幀尋找變換組件。同樣,支持腳本組件。你可以使用GetComponent獲取組件或其他快捷屬性。
20.如果沒有必要不要調用函數(shù)
最簡單,最好的優(yōu)化是執(zhí)行最少的工作。如,當一個敵人在遠處時,讓他處于睡眠狀態(tài),大多時候是可行的。直到玩家靠近,可以這樣處理:
- function Update ()
- {
- // Early out if the player is too far away. if (Vector3.Distance(transform.position, target.position) > 100)
- return;
- perform real work work...
- }
這 并不是很好的方法,雖然Unity不得不在每一幀訪問update函數(shù)。更好的方法是禁用這個行為直到玩家靠近。有3中方法做這個:使用 OnBecameVisible和OnBecameInvisible。這些調用與渲染系統(tǒng)相聯(lián)系。一旦攝像機看到物體,OnBecameVisible 將被調用,不看他時,OnBecameInvisible被調用。這有時很有用。但是對于AI來講通常是沒有用的,因為你背轉敵人,敵人就變成不可用了。
- function OnBecameVisible () {
- enabled = true;
- }
-
- function OnBecameInvisible ()
- {
- enabled = false;
- }
21.使用觸發(fā)器。一個簡單的球形觸發(fā)器能引發(fā)驚人效果。你可以調用OnTriggerEnter/Exit,當進入你想要的作用范圍。
- function OnTriggerEnter (c : Collider)
- {
- if (c.CompareTag("Player"))
- enabled = true;
- }
-
- function OnTriggerExit (c : Collider)
- {
- if (c.CompareTag("Player"))
- enabled = false;
- }
22.使用協(xié)同程序。Update的問題是他在每幀都發(fā)生。很可能只需要5秒鐘檢查一次玩家的距離。這可以節(jié)約大量的處理周期。
......
最后的最后:
感覺還有好多沒涉及到,希望大家有好的建議可以再下面留言,相互學習哦!