對.NET垃圾回收機制的初略理解

程序員首先是人,不是所有人都是細心的,更何況細心的人也會有粗心的時候,因此經常會出現忘了釋放已經使用完的資源,導致資源緊張。有時候是不願去做這些掃尾的事情,因爲覺得他的時間應該是用在更偉大更崇高的事業上面,至於清理垃圾這些雞毛蒜皮的事實在不值得他一屑。於是就有了垃圾回收機制,既減輕了程序員的負擔,也避免了資源的泄漏,一舉兩得。

首先了解一下對象的整個生命過程: 

 1.給對象分配內存;

 2.調用對象構造器進行初始化;

 3.使用資源通過訪問對象成員;

 4.銷燬對象;主要是通過Finalization,Dispose和Close方法

 5.釋放內存。

  垃圾回收會在第1步和第5步發生。在第5步進行垃圾回收比較好理解,第1步是如何觸發垃圾回收的呢?第1步包含三個過程:首先根據類型成員所需空間總合,然後加上兩個額外開銷:類型指針(type object pointer)和同步模塊索引(sync block index),32位系統下一般是8bytes,64位則是16bytes,最後就是判斷當前託管堆中是否有足夠的空間去分配這個對象。當滿足時就爲對象分配所需要的內存,如果不滿足就會觸發垃圾回收,如果垃圾回收後依然不滿足則拋出內存不足的異常。另外分配內存是連續分配的,而且在同一時間段裏分配內存的那些對象一般都有很強的聯繫,比如FileStream和BinaryWriter,連續分配就會使訪問命中率提高,使得性能優化。

  關鍵的問題在於垃圾回收器如何知道哪些對象是垃圾,哪些對象是依然在使用的呢?在CLR中,將那些不再被引用的對象被認爲是可以被回收的。但對象之間有時候會存在複雜的調用關係,這個時候就需要尋根溯源,找到源頭後,將這一系列的對象都標示爲正在使用的,直到遍歷完所有的源頭,那些沒被標示的就可以被認爲是垃圾被回收掉。那麼源頭是什麼呢?在CLR中有個根(root)的概念,每個應用程序都有一系列的根,根是一個存儲位置,它保存着一個指向引用類型對象的指針。因此局部變量,全局變量,靜態變量,方法參數以及指向託管堆中對象的CPU寄存器都是根。顯然值類型變量是不會爲根的。在標記和回收之後還有一個過程,夯實(compact)。 垃圾回收器掃描託管堆,找到連續的內存塊,然後移動未回收的對象到更低的地址, 以得到整塊的內存,同時所有的對象引用都將被調整爲指向對象新的存儲位置。

  CLR垃圾回收機制中還有個很重要的概念,代(generation)。其主要目的是提高垃圾回收的性能。一般分爲3代:0代,1代和2代。0代是新建對象和從未經過垃圾回收對象的集合,1代則是在0代回收過程中未被回收的對象集合,2代是最後一代,也就是經歷至少兩次回收風暴後依然堅挺的對象的集合


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章