瞭解自動記憶體管理,記憶體管理

來源:互聯網
上載者:User

瞭解自動記憶體管理,記憶體管理
瞭解自動記憶體管理


當建立對象、 字串或數組時,從中央池中稱為分配儲存它所需的記憶體。該項目時不再使用,它一次佔用的記憶體可以回收,並用於別的東西。在過去,它通常是由程式員來分配和釋放這些塊堆記憶體使用量適當的函數調用顯式。如今,像統一的單引擎的運行時系統會自動為您管理記憶體。自動記憶體管理需要少比顯式分配/釋放的編碼工作,極大地減少了潛在的記憶體流失 (情況在哪裡記憶體配置,但永遠不會隨後釋放)。

值和參考型別

當一個函數被調用時,其參數的值複製到為這一具體要求保留的記憶體地區。可以複製佔用只有幾個位元組的資料類型,非常迅速和容易。然而,這是常見的對象、字串和數組要大得多,如果這些類型的資料被複製在週期性基礎上,它將會非常低效。幸運的是,這不是必要的 ;從堆分配一個大的項目的實際儲存空間和一個小的"指標"值,用來記住它的位置。從那時起,只有指標需要複製期間傳遞的參數。只要運行時系統可以找到由指標標識的項,可以作為必要時經常使用資料的單個副本。

直接儲存和複製期間參數傳遞的類型稱為值類型。這些包括整數、 浮點數、 布爾值和統一的結構類型(例如,顏色和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;
}
 
 

這裡關鍵的細節是新片不會添加到地方中的字串、 一個接一個。到底發生了什麼是周圍迴圈的每次行變數上以前的內容變得死寂了 — —一個全新的字串分配包含原片加末尾的新部分。因為字串擷取與增加值的我更長的時間,所用的堆空間正在消耗也增加,所以它是容易使用了數百個位元組的可用堆空間的每次調用此函數。如果您需要將許多字串串連在一起更好的選擇是單聲道庫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上維基百科的頁面,可以找到有關對象池的進一步資訊.

 


C# 什是自動記憶體管理?

自動記憶體管理是公用語言運行庫在託管執行過程過程中提供的服務之一。公用語言運行庫的記憶體回收行程為應用程式管理記憶體的分配和釋放。對開發人員而言,這就意味著在開發託管應用程式時不必編寫執行記憶體管理工作的代碼。自動記憶體管理可解決常見問題,例如,忘記釋放對象並導致記憶體流失,或嘗試訪問已釋放對象的記憶體。
 
JAVA的自動記憶體管理是為何

1、Java的記憶體管理就是對象的分配和釋放問題。
在Java中,程式員需要通過關鍵字new為每個對象申請記憶體空間 (基本類型除外),所有的對象都在堆 (Heap)中分配空間。
對象的釋放是由GC決定和執行的。
在Java中,記憶體的分配是由程式完成的,而記憶體的釋放是有GC完成的,這種收支兩條線的方法簡化了程式員的工作。但也加重了JVM的工作。這也是Java程式運行速度較慢的原因之一。

GC釋放空間方法:
監控每一個對象的運行狀態,包括對象的申請、引用、被引用、賦值等。當該對象不再被引用時,釋放對象。

2、記憶體管理結構
Java使用有向圖的方式進行記憶體管理,對於程式的每一個時刻,我們都有一個有向圖表示JVM的記憶體配置情況。

將對象考慮為有向圖的頂點,將參考關聯性考慮為圖的有向邊,有向邊從引用者指向被引對象。另外,每個線程對象可以作為一個圖的起始頂點,例如大多程式從main進程開始執行,那麼該圖就是以main進程頂點開始的一棵根樹。在這個有向圖中,根頂點可達的對象都是有效對象,GC將不回收這些對象。如果某個對象 (連通子圖)與這個根頂點不可達(注意,該圖為有向圖),那麼我們認為這個(這些)對象不再被引用,可以被GC回收。

3、使用有向圖方式管理記憶體的優缺點
Java使用有向圖的方式進行記憶體管理,可以消除引用迴圈的問題,例如有三個對象,相互引用,只要它們和根進程不可達的,那麼GC也是可以回收它們的。
這種方式的優點是管理記憶體的精度很高,但是效率較低。

++:
另外一種常用的記憶體管理技術是使用計數器,例如COM模型採用計數器方式管理構件,它與有向圖相比,精度行低(很難處理循環參考的問題),但執行效率很高。

★ Java的記憶體泄露
Java雖然由GC來回收記憶體,但也是存在泄露問題的,只是比C++小一點。

1、與C++的比較
c++所有對象的分配和回收都需要由使用者來管理。即需要管理點,也需要管理邊。若存在不可達的點,無法在回收分配給那個點的記憶體,導致記憶體泄露。存在無用的對象引用,自然也會導致記憶體泄露。
Java由GC來管理記憶體回收,GC將回收不可達的對象佔用的記憶體空間。所以,Java需要考慮的記憶體泄露問題主要是那些被引用但無用的對象——即指要管理邊就可以。被引用但無用的對象,程式引用了該對象,但後續不會再使用它。它佔用的記憶體空間就浪費了。
如果存在對象的引用,這個對象就被定義為“活動的”,同時不會被釋放。

2、Java記憶體泄露處理
處理Java的記憶體泄露問題:確認該對象不再會被使用。
典型的做法——
把對象資料成員設為null
從集合中移除該對象
注意,當局部變數不需要時,不需明顯的設為null,因為一個方法執行完畢時,這些引用會自動被清理。

例子:
List myList=new ArrayList();
for (int i=1;i<100; i++)
{
Object o=new Object();
myList.add(o);
o=null;
}
//此時,所有的Object對象都沒有被釋放,因為變數myList引用這些對象。

當myList後來不再用到,將之設為null,釋放所有它引用的對象。之後GC便會回收這些對象佔用的記憶體。

★ 對GC操作
對GC的操作並不一定能達到管理記憶體的效果。

G......餘下全文>>
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.