gaopoadmin在32位的Windows作業系統中,每個進程都可以使用4GB的記憶體,這得益於虛擬定址技術,在這4GB的記憶體中儲存著可執 行代碼、代碼載入的DLL和程式啟動並執行所有變數,在C#中,虛擬記憶體中有個兩個儲存變數的地區,一個稱為堆棧,一個稱為託管堆,託管堆的出現是.net不 同於其他語言的地方,堆棧儲存實值型別資料,而託管堆儲存參考型別如類、對象,並受垃圾收集器的控制和管理。在堆棧中,一旦變數超出使用範圍,其使用的記憶體 空間會被其他變數重新使用,這時其空間中儲存的值將被其他變數覆蓋而不複存在,但有時候我們希望這些值仍然存在,這就需要託管堆來實現。我們用幾段代碼來 說明其工作原理,假設已經定義了一個類class1:
class1 object1;
object1=new class1();
第一句定義了一個class1的引用,實質上只是在堆棧中分配了一個4個位元組的空間,它將用來存府後 來執行個體化對象在託管堆中的地址,在windows中這需要4個位元組來表示記憶體位址。第二句執行個體化object1對象,實際上是在託管堆中開僻了一個記憶體空 間來儲存類class1的一個具體對象,假設這個對象需要36個位元組,那麼object1指向的實際上是在託管堆一個大小為36個位元組的連續記憶體空間開始 的地址。由此也可以看出在C#編譯器中為什麼不允許使用未執行個體化的對象,因為這個對象在託管堆中還不存在。當對象不再使用時,這個被儲存在堆棧中的引用變 量將被刪除,但是從上述機制可以看出,在託管堆中這個引用指向的對象仍然存在,其空間何時被釋放取決垃圾收集器而不是引用變數失去範圍時。
在使用電腦的過程中大家可能都有過這種經驗:電腦用久了以後程式運行會變得越來越慢,其中一個重要原因就是系統中存在大量記憶體片段,就是因為程式反 複在堆棧中建立和釋入變數,久而久之可用變數在記憶體中將不再是連續的記憶體空間,為了定址這些變數也會增加系統開銷。在.net中這種情形將得到很大改善, 這是因為有了垃圾收集器的工作,垃圾收集器將會壓縮託管堆的記憶體空間,保證可用變數在一個連續的記憶體空間內,同時將堆棧中引用變數中的地址改為新的地址, 這將會帶來額外的系統開銷,但是,其帶來的好處將會抵消這種影響,而另外一個好處是,程式員將不再花上大量的心思在內在泄露問題上。
當然,以C#程式中不僅僅只有參考型別的變數,仍然也存在實值型別和其他託管堆不能管理的對象,如果檔案名稱柄、網路連接和資料庫連接,這些變數的釋放仍需要程式員通過解構函式或IDispose介面來做。
另一方面,在某些時候C#程式也需要追求速度,比如對一個含用大量成員的數組的操作,如果仍使用傳統的類來操作,將不會得到很好的效能,因為數組在 C#中實際是System.Array的執行個體,會儲存在託管堆中,這將會對運算造成大量的額外的操作,因為除了垃圾收集器除了會壓縮託管堆、更新引用地 址、還會維護託管堆的資訊列表。所幸的是C#中同樣能夠通過不安全的程式碼使用C++程式員通常喜歡的方式來編碼,在標記為unsafe的代碼塊使用指標,這 和在C++中使用指標沒有什麼不同,變數也是存府在堆棧中,在這種情況下聲明一個數組可以使用stackalloc文法,比如聲明一個儲存有50個 double類型的數組:
double* pDouble=stackalloc double[50]
stackalloc會給pDouble數組在堆棧中分配50個double類型大小的記憶體空間,可以使用pDouble[0]、* (pDouble+1)這種方式運算元組,與在C++中一樣,使用指標時必須知道自己在做什麼,確保訪問的正確的記憶體空間,否則將會出現無法預料的錯誤。
掌握託管堆、堆棧、垃圾收集器和不安全的程式碼的工作原理和方式,將有助於你成為真正的優秀C#程式員。
引用:http://hi.baidu.com/lvzybd/blog/item/46b3b4bf8f40420e18d81fd6.html