.net 垃圾回收

.net 垃圾回收

垃圾回收器幫我們處理了內存中不在使用的對象,提高了機器的性能,讓開發人員輕鬆了很多。

你真的瞭解垃圾回收嗎?

或許你知道垃圾回收,聽說過是通過標記回收,可是怎麼標記回收呢就不是很清楚了,好吧,如果不清楚就繼續往下看。如果你是大神對這塊瞭如執掌,請直接跳過,歡迎來提不同的意見。

1、我們先來聊一下內存分配:

代碼中聲明變量是需要向內存申請地址的,內存呢又分託管堆和棧,我們今天主要聊的就是託管堆內存

啥事託管堆內存呢?想必各位也心中知道,不知道的自行百度谷歌去。

寫代碼中凡是需要使用new聲明的變量都是引用類型變量,使用的都是託管堆內存地址,那聲明瞭一個對象,需要分配多大的控件呢?

1.1、這個時候就需要計算類型的字段需要的字節數了

1.2、引用類型對象開銷的字節數還需要(類型對象指針和同步索引塊)

在32位應用中,這多出來的兩個字段各需32位字節地址空間,所以每個對象需要多佔用8個字節的地址控件

在64位應用中,這多出來的兩個字段各需64位字節地址空間,所以每個對象需要多佔用16個字節的地址控件

1.3、內存申請後,CLR會檢查保留區是否能夠提供分配對象所需的字節數,使用new 聲明的對象會向託管堆請求地址分配,並返回對象地址,NextObjPtr指針會加上對象佔據的字節數,得到一個新值

2、垃圾回收-Go Go Go

垃圾回收的基本邏輯:垃圾回收器會檢查託管堆中是否又應用程序不再使用的任何對象,如果有,它們使用的內存就可以回收了。

回收之前的託管堆如下:

下面我們來聊一下標記回收的整個過程:

2.1、首先,應用有一組根(root)每個根都是一個存儲位置,其中包含指向引用類型對象的一個指針,指針要麼引用託管堆中的一個對象,要麼爲null

例如:類型中定義的任何靜態字段被認爲是一個根

任何方法參數或局部變量也被認爲是一個根,只有引用類型的變量才被認爲是一個根,值類型不能被認爲是根。

2.2、垃圾回收的第一階段,標記階段:

這時,垃圾回收器會沿着線程棧上行以檢查所有根,如果發現一個根引用了一個對象,就在對象 “同步索引塊”上開啓一位---標記,

以遞歸的方式遍歷所有可達的對象。如果垃圾回收器試圖標記一個先前標記過的對象,就會停止沿這個路徑走下去。

這個行爲有兩個目的:

1、垃圾回收器不會多次遍歷一個對象,所以性能得到顯著增強

2、如果對象存在循環鏈表,可以避免無線循環。

檢查完所有的根之後,堆中將包含一組已標記和未標記的對象,已標記的對象是代碼可達的對象,而未標記的對象是不可達的,不可達的對象被認爲是垃圾,它們佔用的內存是可以被回收的

垃圾回收之後的託管堆如下:

2.3、垃圾回收的第二階段,壓縮階段:

這個時候該回收內存空間已經都回收了,空出來的內存可能是前頭一塊,中間一塊,後邊又一塊。

垃圾回收器線性遍歷堆,以尋找未標記對象的連續內存塊,如果發現內存塊比較小,則忽略,如果發現大的,可用的連續內存塊,垃圾回收器會把非垃圾的對象移動到這裏以壓縮堆。

參考:CLR Via C#(第三版)

原文地址https://www.cnblogs.com/miao817/p/12705140.html

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