1. 程式人生 > 其它 >基礎一 基礎語法 記憶體管理和垃圾回收

基礎一 基礎語法 記憶體管理和垃圾回收

摘抄 https://www.cnblogs.com/edisonchou/p/4787775.html

NET中棧和堆的差異

每一個.NET應用程式最終都會執行在一個OS程序中,假設這個OS的傳統的32位系統,那麼每個.NET應用程式都可以擁有一個4GB的虛擬記憶體。.NET會在這個4GB的虛擬記憶體塊中開闢三塊記憶體作為 堆疊託管堆 以及 非託管堆

  (1).NET中的堆疊

  堆疊用來儲存值型別的物件和引用型別物件的引用(地址),其分配的是一塊連續的地址,如下圖所示,在.NET應用程式中,堆疊上的地址從高位向低位分配記憶體,.NET只需要儲存一個指標指向下一個未分配記憶體的記憶體地址即可。

  對於所有需要分配的物件,會依次分配到堆疊中,其釋放也會嚴格按照棧的邏輯(FILO,先進後出)依次進行退棧。(這裡的“依次”是指按照變數的作用域進行的),假設有以下一段程式碼:

 TempClass a = new TempClass();
    a.numA = 1;
    a.numB = 2;

其在堆疊中的記憶體圖如下圖所示:

  這裡TempClass是一個引用型別,擁有兩個整型的int成員,在棧中依次需要分配的是a的引用,a.numA和a.numB。當a的作用域結束之後,這三個會按照a.numB→a.numA→a的順序依次退棧。

(2).NET中的託管堆

  眾所周知,.NET中的引用型別物件時分配在託管堆上的,和堆疊一樣,託管堆也是程序記憶體空間中的一塊區域。But,託管堆的記憶體分配卻和堆疊有很大區別。受益於.NET記憶體管理機制,託管堆的分配也是連續的(從低位到高位),

但是堆中卻存在著暫時不能被分配卻已經無用的物件記憶體塊

 

 如上圖所示,.NET程式通過分配在堆疊中的引用來找到分配在託管堆的物件例項。當堆疊中的引用退出作用域時,這時僅僅就斷開和實際物件例項的引用聯絡。而當託管堆中的記憶體不夠時,.NET會開始執行GC(垃圾回收)機制。GC是一個非常複雜的過程,它不僅涉及託管堆中物件的釋放,而且需要移動合併託管堆中的記憶體塊。當GC之後,堆中不再被使用的物件例項才會被部分釋放(注意並不是完全釋放),而在這之前,它們在堆中是暫時不可用的。在C/C++中,由於沒有GC,因此可以直接free/delete來釋放記憶體。

(3).NET中的非託管堆

  .NET程式還包含了非託管堆,所有需要分配堆記憶體的非託管資源將會被分配到非託管堆上。非託管的堆需要程式設計師用指標手動地分配和釋放記憶體,.NET中的GC和記憶體管理不適用於非託管堆

,其記憶體塊也不會被合併移動,所以非託管堆的記憶體分配是按塊的、不連續的。因此,這也解釋了我們為何在使用非託管資源(如:檔案流、資料庫連線等)需要手動地呼叫Dispose()方法進行記憶體釋放的原因。