您的位置:首頁>正文

瞭解自動記憶體管理

瞭解自動記憶體管理

當創建物件、 字串或陣列時, 從中央池中稱為堆分配存儲它所需的記憶體。 該項目時不再使用, 它1次佔用的記憶體可以回收, 並用於別的東西。 在過去, 它通常是由http://www.wfuyu.com來分配和釋放這些塊堆記憶體使用適當的函式呼叫顯式。 如今, 像統1的單引擎的運行時系統會自動為您管理記憶體。 自動記憶體管理需要少比顯式分配/釋放的編碼工作, 極大地減少了潛伏的記憶體洩漏 (情況在哪裡記憶體分配, 但永久不會隨後釋放)。

值和援用類型

當1個函數被調用時, 其參數的值複製到為這1具體要求保存的記憶體區域。

可以複製佔用只有幾個位元組的資料類型, 非常迅速和容易。 但是, 這是常見的物件、字串和陣列要大很多, 如果這些類型的資料被複製在定期的基礎上, 它將會非常低效。 榮幸的是, 這不是必要的 ;從堆分配1個大的專案的實際存儲空間和1個小的"指針"值, 用來記住它的位置。 從那時起, 只有指標需要複製期間傳遞的參數。 只要運行時系統可以找到由指標標識的項, 可以作為必要時常常使用資料的單個副本。

直接存儲和複製期間參數傳遞的類型稱為數值型別。 這些包括整數、 浮點數、 布林值和統1的結構類型(例如, 色彩和Vector3)。 在堆上分配, 然後通過指標訪問的類型稱為援用類型, 由於只是存儲在變數中的值"是指"真實的資料。

援用類型的例子包括物件、 字串和陣列。

分配和垃圾回收

記憶體管理器跟蹤的領域它明知是未使用的堆中。 當1座新的記憶體要求時 (說當1個物件被產生實體)時, 經理選擇要從中分配塊未使用的區域, 然後從已知未使用的空間中刪除已分配的記憶體。 後續要求的處理方式相同, 直到沒有自由的範圍不夠大, 沒法分配所需的塊大小。 在這1點上是極不可能從堆中分配的所有記憶體都都仍在使用。 只能訪問堆上的參考項目, 只要仍有可以找到它的援用變數。 如果指向的區塊的所有援用都都不見了(即, 援用變數已被重新分配或它們都是都現已超越範圍的本地變數) 然後它佔用的記憶體可以安全地重新分配。

要肯定哪堆塊不再使用, 記憶體管理器搜索所有當前活動的援用變數, 並標誌著他們稱為"活著"的塊。 在搜索結束後, 任何活塊之間的空間被認為是空的記憶體管理器, 可以用於後續分配。 緣由很明顯, 定位和釋放未使用的記憶體的進程被稱為垃圾搜集(或簡稱 GC)。

優化

垃圾搜集是自動與不可見的http://www.wfuyu.com, 但搜集進程實際上需要大量的 CPU時間, 在幕後。 如果應用得當, 自動記憶體管理通常將等於或擊敗手動分配, 以整體的性能。 但是, 相當重要的是對http://www.wfuyu.com來講, 避免毛病, 將觸發比必要更常常搜集器並介紹在履行暫停。

有1些臭名昭著的演算法, 可以是 GC的噩夢, 雖然他們看起來無辜乍1看。 重複字元串聯接是1個經典的例子:-

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

這裡關鍵的細節是新片不會添加到地方中的字串、 1個接1個。 到底產生了甚麼是周圍迴圈的每次行變數上之前的內容變得死寂了 ― ―1個全新的字串分配包括原片加末尾的新部份。 由於字串獲得與增加值的我更長的時間, 所用的堆空間正在消耗也增加, 所以它是容易使用了數百個位元組的可用堆空間的每次調用此函數。 如果您需要將許多字元串聯接在1起更好的選擇是單聲道庫System.Text.StringBuilder類。

但是, 即便重複的串連不會造成太多的麻煩, 除非它叫做頻繁, 並在通常意味著該框架的統1更新。 就像:-

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

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

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

當1個函數返回陣列值時產生的另外一個潛伏的問題:-

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

這類類型是函數的非常優雅, 交通便捷, 當創建1個新陣列, 用值填充。 但是, 如果它反復調用然後新鮮記憶體將分配每次。 由於陣列可以是很大, 可用堆空間可以得到使用迅速上升, 致使頻繁的垃圾回收。 若要避免此問題的1種方法是要使用的陣列是1個援用類型的事實。 可以在這個函數中修改成1個函數作為參數傳遞的陣列和結果不會在函數返回後。 像上面常常被替換之類的功能:-

functionRandomList(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]();}

但是,你應當謹慎使用這類技術,檢查事件探查器統計資訊,以確保它真的減少搜集時間為你的遊戲。

大堆與緩慢但很少產生垃圾回收

這1戰略合適的遊戲撥款 (和集合) 是相對較少,可以在遊戲暫停期間處理。它是用於堆是1樣大的而不是如此之大,讓您的利用程式由於系統記憶體不足 OS被殺害。但是,單聲道的運行時避免擴大堆自動如果可能的話。您可以通過在啟動進程中預1些預留位置空間手動擴大堆 (即您產生實體1個純潔的影響,記憶體管理器分配的"無用"對象):-

functionStart() {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 blocksfor (var i : int = 0; i < 1024; i++)tmp[i] = new byte[1024];// release referencetmp = null;}

1個足夠大的堆應當不得到完全填滿那些暫停遊戲,可以容納1個集合之間。這樣的停頓時,您可以顯式要求集合:-

System.GC.Collect();

再次,你應當照顧使用此策略時,注意到探查器統計資訊而不只在假定它有預期的效果。

可重用的物件集區

有很多情況下,在那裡您可以免生成垃圾僅通過減少創建和燒毀的物件的數目。有某些類型的物件在遊戲中,如子彈頭,可能會遇到幾遍,即便只有1小部份曾將播放1次。在這類情況下,很有可能要重用的物件,而不是摧毀舊的並替換為新的。

進1步的資訊

記憶體管理是奧妙和複雜須大量的學術努力1直致力。如果你有興趣學習更多有關它memorymanagement.org是1種優秀的資源,列出了許多出版物和線上文章。在Sourcemaking.com上維琪百科的頁面,可以找到有關物件集區的進1步資訊.

它最好盡可能避免分配。不過,既然他們不能完全消除,但也有兩個主要的策略,你可使用盡可能減少它們侵入遊戲:-

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

這類策略常常是遊戲的最好的有長時間在哪裡光滑的畫面播放速率是遊戲的主要關注的遊戲。這樣的比賽通常會頻繁地分配小塊,但這些塊將只扼要地被使用。在 iOS上使用這類策略時的典型堆大小是大約 200 KB,垃圾回收會約5ms的 iPhone 3g。如果堆增加到 1 MB時,該集合將約 7ms。因此,它可以有益於有時要求普通幀間隔的垃圾回收。這通常會使集合比嚴格必須更常常產生,但他們將處理速度快、 影響最小的遊戲:-

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

但是,你應當謹慎使用這類技術,檢查事件探查器統計資訊,以確保它真的減少搜集時間為你的遊戲。

大堆與緩慢但很少產生垃圾回收

這1戰略合適的遊戲撥款 (和集合) 是相對較少,可以在遊戲暫停期間處理。它是用於堆是1樣大的而不是如此之大,讓您的利用程式由於系統記憶體不足 OS被殺害。但是,單聲道的運行時避免擴大堆自動如果可能的話。您可以通過在啟動進程中預1些預留位置空間手動擴大堆 (即您產生實體1個純潔的影響,記憶體管理器分配的"無用"對象):-

functionStart() {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 blocksfor (var i : int = 0; i < 1024; i++)tmp[i] = new byte[1024];// release referencetmp = null;}

1個足夠大的堆應當不得到完全填滿那些暫停遊戲,可以容納1個集合之間。這樣的停頓時,您可以顯式要求集合:-

System.GC.Collect();

再次,你應當照顧使用此策略時,注意到探查器統計資訊而不只在假定它有預期的效果。

可重用的物件集區

有很多情況下,在那裡您可以免生成垃圾僅通過減少創建和燒毀的物件的數目。有某些類型的物件在遊戲中,如子彈頭,可能會遇到幾遍,即便只有1小部份曾將播放1次。在這類情況下,很有可能要重用的物件,而不是摧毀舊的並替換為新的。

進1步的資訊

記憶體管理是奧妙和複雜須大量的學術努力1直致力。如果你有興趣學習更多有關它memorymanagement.org是1種優秀的資源,列出了許多出版物和線上文章。在Sourcemaking.com上維琪百科的頁面,可以找到有關物件集區的進1步資訊.

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示