首先堆棧和堆(托管堆)都在進程的虛擬內(nèi)存中。(在32位處理器上每個進程的虛擬內(nèi)存為4GB) 堆棧stack 堆棧中存儲值類型。 堆棧實際上是向下填充,即由高內(nèi)存地址指向地內(nèi)存地址填充。 堆棧的工作方式是先分配內(nèi)存的變量后釋放(先進后出原則)。 堆棧中的變量是從下向上釋放,這樣就保證了堆棧中先進后出的規(guī)則不與變量的生命周期起沖突! 堆棧的性能非常高,但是對于所有的變量來說還不太靈活,而且變量的生命周期必須嵌套。 通常我們希望使用一種方法分配內(nèi)存來存儲數(shù)據(jù),并且方法退出后很長一段時間內(nèi)數(shù)據(jù)仍然可以使用。此時就要用到堆(托管堆)!
堆(托管堆)heap 堆(托管堆)存儲引用類型。 此堆非彼堆,.NET中的堆由垃圾收集器自動管理。 與堆棧不同,堆是從下往上分配,所以自由的空間都在已用空間的上面。 比如創(chuàng)建一個對象: Customer cus; cus = new Customer(); 申明一個Customer的引用cus,在堆棧上給這個引用分配存儲空間。這僅僅只是一個引用,不是實際的Customer對象! cus占4個字節(jié)的空間,包含了存儲Customer的引用地址。 接著分配堆上的內(nèi)存以存儲Customer對象的實例,假定Customer對象的實例是32字節(jié),為了在堆上找到一個存儲Customer對象的存儲位置。 .NET運行庫在堆中搜索第一個從未使用的,32字節(jié)的連續(xù)塊存儲Customer對象的實例! 然后把分配給Customer對象實例的地址賦給cus變量!
從這個例子中可以看出,建立對象引用的過程比建立值變量的過程復(fù)雜,且不能避免性能的降低! 實際上就是.NET運行庫保存對的狀態(tài)信息,在堆中添加新數(shù)據(jù)時,堆棧中的引用變量也要更新。性能上損失很多! 有種機制在分配變量內(nèi)存的時候,不會受到堆棧的限制:把一個引用變量的值賦給一個相同類型的變量,那么這兩個變量就引用同一個堆中的對象。 當一個應(yīng)用變量出作用域時,它會從堆棧中刪除。但引用對象的數(shù)據(jù)仍然保留在堆中,一直到程序結(jié)束 或者 該數(shù)據(jù)不被任何變量應(yīng)用時,垃圾收集器會刪除它。 |
|
來自: TivonStone > 《技術(shù)摘要》