1. 程式人生 > >了解自己主動內存管理

了解自己主動內存管理

出版 make system .text 戰略 出了 void 都是 結果

??

了解自己主動內存管理


當創建對象、 字符串或數組時。從中央池中稱為分配存儲它所需的內存。該項目時不再使用。它一次占用的內存能夠回收,並用於別的東西。在過去,它一般是由程序猿來分配和釋放這些塊堆內存使用適當的函數調用顯式。現在,像統一的單引擎的執行時系統會自己主動為您管理內存。

自己主動內存管理須要少比顯式分配/釋放的編碼工作,極大地降低了潛在的內存泄漏 (情況在哪裏內存分配。但永遠不會隨後釋放)。

值和引用類型

當一個函數被調用時。其參數的值拷貝到為這一詳細要求保留的內存區域。能夠復制占用僅僅有幾個字節的數據類型。非常迅速和easy。然而,這是常見的對象、字符串和數組要大得多。假設這些類型的數據被復制在定期的基礎上,它將會非常低效。

幸運的是。這不是必要的 。從堆分配一個大的項目的實際存儲空間和一個小的"指針"值,用來記住它的位置。從那時起,僅僅有指針須要復制期間傳遞的參數。僅僅要執行時系統能夠找到由指針標識的項。能夠作為必要時常常使用數據的單個副本。

直接存儲和復制期間參數傳遞的類型稱為值類型。這些包含整數、 浮點數、 布爾值和統一的結構類型(比如,顏色和Vector3)。

在堆上分配,然後通過指針訪問的類型稱為引用類型。由於僅僅是存儲在變量中的值"是指"真實的數據。

引用類型的樣例包含對象、 字符串和數組。

分配和垃圾回收

內存管理器跟蹤的領域它明知是未使用的堆中。當一座新的內存請求時 (說當一個對象被實例化)時。經理選擇要從中分配塊未使用的區域,然後從已知未使用的空間中刪除已分配的內存。

興許請求的處理方式同樣。直到沒有自由的範圍不夠大。無法分配所需的塊大小。在這一點上是極不可能從堆中分配的全部內存都都仍在使用。僅僅能訪問堆上的參考項目。僅僅要仍有能夠找到它的引用變量。

假設指向的內存塊的全部引用都都不見了(即,引用變量已被又一次分配或它們都是都現已超出範圍的本地變量) 然後它占用的內存能夠安全地又一次分配。

要確定哪堆塊不再使用,內存管理器搜索全部當前活動的引用變量。並標誌著他們稱為"活著"的塊。

在搜索結束後。不論什麽活塊之間的空間被覺得是空的內存管理器,能夠用於興許分配。原因非常明顯,定位和釋放未使用的內存的過程被稱為垃圾收集(或簡稱 GC)。

優化

垃圾收集是自己主動與不可見的程序猿,但收集過程實際上須要大量的 CPU

時間。在幕後。假設運用得當。自己主動內存管理通常將等於或擊敗手動分配,以總體的性能。然而。至關重要的是對於程序猿來說。避免錯誤。將觸發比必要更常常收集器並介紹在執行暫停。

有一些臭名昭著的算法,能夠是 GC的噩夢。雖然他們看起來無辜乍一看。反復字符串連接是一個經典的樣例:-

function ConcatExample(intArray: int[]) {
??? var line = intArray[0].ToString();
??? 
????for (i = 1; i < intArray.Length; i++) {
??????? line += ", " + intArray[i].ToString();
??? }
??? 
????return line;
}
?
?

這裏關鍵的細節是新片不會加入到地方中的字符串、 一個接一個。

究竟發生了什麽是周圍循環的每次行變量上以前的內容變得死寂了 — —一個全新的字符串分配包含原片加末尾的新部分。

由於字符串獲取與添加值的我更長的時間,所用的堆空間正在消耗也添加,所以它是easy使用了數百個字節的可用堆空間的每次調用此函數。

假設您須要將很多字符串連接在一起更好的選擇是單聲道庫System.Text.StringBuilder類。

然而,即使反復的串聯不會造成太多的麻煩。除非它叫做頻繁,並在通常意味著該框架的統一更新。就像:-

var scoreBoard: GUIText;
var score: int;
?
function Update() {
??? var scoreText: String = "Score: " + score.ToString();
??? scoreBoard.text = scoreText;
}
?
?

你何時分配新的字符串調用 Update時每次和生成新的垃圾不斷淌出。大多數是能夠通過更新文本,僅當比分更改時保存:-

var scoreBoard: GUIText;
var scoreText: String;
var score: int;
var oldScore: int;
?
function Update() {
??? if (score != oldScore) {
??????? scoreText = "Score: " + score.ToString();
??????? scoreBoard.text = scoreText;
??????? oldScore = score;
??? }
}
?
?

當一個函數返回數組值時發生的還有一個潛在的問題:-

function RandomList(numElements: int) {
??? var result = new float[numElements];
??? 
????for (i = 0; i < numElements; i++) {
??????? result[i] = Random.value;
??? }
??? 
????return result;
}
?
?

這樣的類型是函數的非常優雅,交通便捷。當創建一個新數組,用值填充。

然而。假設它反復調用然後新奇內存將分配每次。由於數組能夠是非常大,可用堆空間能夠得到使用迅速上升。導致頻繁的垃圾回收。若要避免此問題的一種方法是要使用的數組是一個引用類型的事實。能夠在這個函數中改動成一個函數作為參數傳遞的數組和結果不會在函數返回後。

像上面常常被替換之類的功能:-

function RandomList(arrayToFill: float[]) {
??? for (i = 0; i < arrayToFill.Length; i++) {
??????? arrayToFill[i] = Random.value;
??? }
}
?
?

這僅僅是用新值替換現有數組的內容。雖然這須要初始分配的數組必須在調用代碼中 (這看起來有點不雅)。該函數將不會產生不論什麽新的垃圾。當它被調用時。

請求集合

如上文所述,它最好盡量避免分配。

只是,既然他們不能全然消除,但也有兩個基本的策略,你能夠使用盡量降低它們侵入遊戲:-

具有高速和頻繁的垃圾回收的小堆

這樣的策略往往是遊戲的最好的有長時間在哪裏光滑的幀速率是遊戲的主要關註的遊戲。

這樣的比賽一般會頻繁地分配小塊,但這些塊將僅僅簡要地被使用。在 iOS上使用這樣的策略時的典型堆大小是大約 200 KB,垃圾回收會約5ms iPhone 3g

假設堆添加到 1 MB時,該集合將約 7ms。因此。它能夠有利於有時要求普通幀間隔的垃圾回收。這一般會使集合比嚴格必需更常常發生。但他們將處理速度快、 影響最小的遊戲:-

if (Time.frameCount % 30 == 0)
{
?? System.GC.Collect]();
}
?
?

然而,你應該慎重使用這樣的技術,檢查事件探查器統計信息,以確保它真的降低收集時間為你的遊戲。

大堆與緩慢但非常少發生垃圾回收

這一戰略適合的遊戲撥款 (和集合) 是相對較少。能夠在遊戲暫停期間處理。它是用於堆是一樣大的而不是如此之大,讓您的應用程序由於系統內存不足 OS被殺害。然而。單聲道的執行時避免擴大堆自己主動假設可能的話。您能夠通過在啟動過程中預一些占位符空間手動擴展堆 (即您實例化一個純粹的影響,內存管理器分配的"無用"對象):-

function Start() {
??? var tmp = new System.Object[1024];
?
??? // make allocations in smaller blocks to avoid them to be treated in a special way, which is designed for large blocks
??????? for (var i : int = 0; i < 1024; i++)
??????? tmp[i] = new byte[1024];
?
??? // release reference
??????? tmp = null;
}
?
?
?

一個足夠大的堆應該不得到全然填滿那些暫停遊戲。能夠容納一個集合之間。這樣的停頓時,您能夠顯式請求集合:-

System.GC.Collect();
?
?

再次。你應該照應使用此策略時,註意到探查器統計信息而不僅僅在假設它有預期的效果。

可重用的對象池

有非常多情況下。在那裏您能夠避免生成垃圾僅通過降低創建和銷毀的對象的數目。有某些類型的對象在遊戲中,如子彈頭。可能會遇到幾遍,即使僅僅有一小部分以前將播放一次。在這樣的情況下,非常有可能要重用的對象,而不是摧毀舊的並替換為新的。

進一步的信息

內存管理是微妙和復雜須大量的學術努力一直致力。假設你有興趣學習很多其它有關它memorymanagement.org是一種優秀的資源,列出了很多出版物和在線文章。在Sourcemaking.com

from=&to=zh-CHS&a=http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FObject_pool_pattern">維基百科的頁面。能夠找到有關對象池的進一步信息.

?

了解自己主動內存管理