.NET垃圾回收機制詳解與心得體會

這幾天對垃圾回收機制有了較爲透徹的理解,在此與朋友們分享一下。首先,讓我們來了解下什麼是垃圾回收機制。

爲了使程序員從跟蹤內存使用的繁重任務中解脫出來,利用充分的時間去完成業務邏輯,因此產生了垃圾回收機制,雖然大多數的垃圾回收器都要求應用程序不停地暫停從而釋放出不在使用的資源,但是.NET的垃圾回收器效率依然很高。

垃圾回收器的基本思想:

      尋找不再使用的對象,將他們從內存中刪除,並壓實託管堆以釋放不在使用的對象所佔用的內存。在堆被壓實之後,所有的對象引用都將被調整爲指向對象新的存儲位置。

垃圾回收機制的功能:用來管理託管資源和非託管資源所佔用的內存分配和釋放。

垃圾回收器的基本假定:

1.     最近被分配的內存空間的對象最有可能需要被釋放。在方法執行時,通常需要爲該方法所使用到的對象分配內存空間,搜索最近被分配的對象集合有助於花費最少的工作來釋放盡可能多的空閒內存空間。

2.     生命期最長的對象需要釋放的可能性最小。在通過幾輪的垃圾回收後仍然存在的對象不大可能是那種能夠在下一輪迴收中被釋放的臨時對象,搜索這些內存塊往往要進行大量的工作,卻只能釋放很小一部分的內存空間。

3.     同時分配內存的對象通常也會同時使用,將同時分配內存的對象的存儲位置彼此相連有助於提高緩存性能,在垃圾回收時也往往是同一批處理或者是遵循後分配,先釋放原則。

 

.NET 框架的垃圾回收器被稱爲分代的垃圾回收器( Generational Garbage Conllector ),也就是說被分配的內存分爲三個類別(生存期等級),或者說分爲三代,即0,1,2三代,對應的託管堆的初始化大小分別是256K2M10M。當垃圾回收器在發現改變託管堆的大小能夠提高性能的話,會改變託管堆的大小。例如:當應用程序實例化了一些佔用內存較少的對象時,而且這些對象所佔用的資源能被很快回收的話,0代託管堆的大小會變爲128K.相反,如果垃圾回收器發現所佔用的資源不能被很快回收的話,會增加託管堆的大小,這時就是512k了。(注意:前提是:當垃圾回收器在發現改變託管堆的大小能夠提高性能的話,纔會改變託管堆的大小。)

最近被分配的內存空間的對象被放置在第0代,一般存儲於二級緩存中,所以能對第0代中的對象實現快速存取。經過一輪垃圾回收後,仍然保留在第0代中的對象則被移進第1代中,再經過一輪垃圾回收後,仍然保留再第1代中的對象則被移進第2代中,第2代中包含了生存期較長的對象,這些對象至少經過了兩輪迴收。

現在來考慮一個問題,爲什麼要將本輪中沒有被回收掉的對象移到下一代中呢?朋友們如果對上面的內容理解了,那麼這個問題的也就迎刃而解了。是的,就是爲了把存取速度較快的空間給置空,分配給最近實例化的對象,爲了提高效率用來實現對象的快速讀取的。

   

現在來看看託管堆上的內存分配問題:

      當程序請求爲某對象分配空間時,託管堆上的指針會指向下一個最近的可用的內存空間,如下圖所示:

 

     

 

由此圖我們可以清晰的知道託管堆的內存分配是線性分配的,

 

當然,這種分配方式的效率也是最高的。而普通的堆對於內存分配是基於內存塊大小的,兩個同時聲明的對象在普通堆上被分配的位置可能相隔較遠,於是降低了緩存的性能。所以,在一個不需要太多垃圾回收的應用程序中,託管堆的表現會優於傳統的堆。

 

 

 

 

 

下面來學習使用終結器[ Finalize()方法]

Protected void Finalize( ) {   Base.Finalize();    }

類提供一個終結器以在對象被銷燬時執行 ,值得注意的是: 當一個對象實現了Finalize方法,垃圾回收器會在它的終結列表(Finalization List)中加入一個指向該對象的指針(終結列表中包含的是等待終結的對象)。

 

等到此輪垃圾回收開始時,垃圾回收器會將該對象的引用置入終結列表,標識此對象爲等待終結的對象,雖然此對象現在仍然存在,但是在應用程序中已經引用不到該對象了。垃圾回收器在此輪使用一個專用的線程,使終結列表中的對象執行終結器,執行完終結器的對象會被此對象標記爲不再需要終結的對象,並從終結列表中除去。

終結完成後,對象所佔用的資源將在下一輪垃圾回收中被回收。

   終結順序是不確定的,但是當某個對象被終結時,由此對象產生都應該已經被終結,大家肯定在想這是爲什麼吧?

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