C#中堆和堆疊的區別

c_link發表於2011-02-27
首先堆疊和堆(託管堆)都在程式的虛擬記憶體中。(在32位處理器上每個程式的虛擬記憶體為4GB)

堆疊stack 

堆疊中儲存值型別。

堆疊實際上是向下填充,即由高記憶體地址指向地記憶體地址填充。

堆疊的工作方式是先分配記憶體的變數後釋放(先進後出原則)。

堆疊中的變數是從下向上釋放,這樣就保證了堆疊中先進後出的規則不與變數的生命週期起衝突!

堆疊的效能非常高,但是對於所有的變數來說還不太靈活,而且變數的生命週期必須巢狀。

通常我們希望使用一種方法分配記憶體來儲存資料,並且方法退出後很長一段時間內資料仍然可以使用。此時就要用到堆(託管堆)!

 

 堆(託管堆)heap

堆(託管堆)儲存引用型別。

此堆非彼堆,.NET中的堆由垃圾收集器自動管理。

與堆疊不同,堆是從下往上分配,所以自由的空間都在已用空間的上面。

比如建立一個物件:

Customer cus;

cus = new Customer();

申明一個Customer的引用cus,在堆疊上給這個引用分配儲存空間。這僅僅只是一個引用,不是實際的Customer物件!

cus佔4個位元組的空間,包含了儲存Customer的引用地址。

接著分配堆上的記憶體以儲存Customer物件的例項,假定Customer物件的例項是32位元組,為了在堆上找到一個儲存Customer物件的儲存位置。

.NET執行庫在堆中搜尋第一個從未使用的,32位元組的連續塊儲存Customer物件的例項!

然後把分配給Customer物件例項的地址賦給cus變數!

 

從這個例子中可以看出,建立物件引用的過程比建立值變數的過程複雜,且不能避免效能的降低!

實際上就是.NET執行庫儲存對的狀態資訊,在堆中新增新資料時,堆疊中的引用變數也要更新。效能上損失很多!

有種機制在分配變數記憶體的時候,不會受到堆疊的限制:把一個引用變數的值賦給一個相同型別的變數,那麼這兩個變數就引用同一個堆中的物件。

當一個應用變數出作用域時,它會從堆疊中刪除。但引用物件的資料仍然保留在堆中,一直到程式結束 或者 該資料不被任何變數應用時,垃圾收集器會刪除它。

相關文章