理解堆與棧對於理解.NET中的記憶體管理、記憶體回收、錯誤和異常、調試與日誌有很大的協助。記憶體回收的機制使程式員從複雜的記憶體管理中解脫出來,雖然絕大多數的C#程式並不需要程式員手動管理記憶體,但這並不代表程式員就無需瞭解分配的對象是如何被回收的,在一些特殊的場合仍需要程式員手動進行記憶體管理。
在32位的處理器上,每個進程的虛擬記憶體為4GB,.NET會在這4GB的記憶體塊中開闢出3塊記憶體,分別作為棧、託管堆、和非託管堆
堆(heap):
堆是從下往上分配,所以已用的空間在自由空間下面,C#中所有參考型別的對象分配在託管堆上,託管堆在記憶體上是連續分配的,並且記憶體對象的釋放受垃圾收集機制的管理,效率相對於棧來說要低的多。
棧(stack):
棧是自上向下進行填充,即由高記憶體位址指向低記憶體位址,並且記憶體配置是連續的,C#中所有的實值型別和參考型別的引用都分配在棧上,棧根據後進先出的原則,依次對分配和釋放記憶體對象。
對象記憶體的分配與銷毀:
當一個類的執行個體對象建立的時候,這個對象的不同成員按類別被分配到了不同的記憶體地區,實值型別和參考型別的指標被分配到了棧上,參考型別的執行個體對象被分配到了託管堆上,靜態成員被分配到了全域資料區。此時棧上的指標會指向堆上的對象。當對象使用完以後,引用和實際對象的聯絡就會斷開,從而從而使對象冬眠。因為棧具有自我維護性,它的記憶體管理可以通過作業系統來完成,而此時堆上的冬眠對象就需要通過記憶體回收行程(GC)使用一定的演算法來進行回收,釋放對象所佔據的記憶體。
C#中的深拷貝與淺拷貝
深拷貝:又稱深度複製,它完全是新對象的產生,不僅複製所有的非靜態實值型別成員,而且複製所有參考型別成員的實際對象。(即棧上和堆上的成員均進行複製)
淺拷貝:又稱影子複製,只複製原始對象中的所有的非靜態實值型別成員和所有參考型別成員的引用,就是說,原始對象和新對象共用所有參考型別成員的對象執行個體。(即只複製棧上的成員)
註:不管是深拷貝還是淺拷貝,都不會複製全域資料區的成員,因為全域資料區的成員是靜態成員,它屬於某一個類,並不屬於類的執行個體對象,因此無法複製。
C#中的深拷貝可以通過實現ICloneable介面來實現,但是在不是必須實現ICloneable介面的情況下,應避免類型繼承ICloneable介面。因為這樣做將強制所有的子類必須實現ICloneable介面,否則子類的新成員將不能被類型的深拷貝所覆蓋。