對C# 中堆棧,堆,實值型別,參考型別的理解對C# 中堆棧,堆,實值型別,參考型別的理解

來源:互聯網
上載者:User

對C# 中堆棧,堆,實值型別,參考型別的理解

1,什麼是GC GC的全稱是garbage collection,中文名稱記憶體回收,是.net中對記憶體管理的一種功能。記憶體回收行程跟蹤並回收託管記憶體中分配的對象,定期執行記憶體回收以回收分配給沒有有效引用的對象的記憶體。當使用可用記憶體不能滿足記憶體請求時,GC會自動進行。在進行記憶體回收時,記憶體回收行程回首先搜尋記憶體中的託管對象,然後從Managed 程式碼中搜尋被引用的對象並標記為有效,接著釋放沒有被標記為有效對象並收回記憶體,最後整理記憶體將有效對象挪動到一起。這就是GC的四個步驟。 由上可見,GC是很影響效能的,所以一般說來這種事情況還是盡量少發生為好。 為了減少一些效能影響,.net的GC支援對象老化,或者說分代的概念,代是對象在記憶體中相對存現時期的度量單位,對象的代數或存現時期說明對象所屬的代。目前.net的記憶體回收行程支援三代。每進行一次GC,沒有被回收的對象就自動提升一代。較近建立的對象屬於較新的代,比在應用程式生命週期中較早建立的對象的代數低。最近代中的對象位於零代中。每一次GC的時候,都首先回收零代中的對象,只有在較低代數的對象回收完成後仍不能滿足需求的情況下才回收較高代數的對象。

2,讀文章,看到了一個關於堆和棧(堆棧)的區別的比喻。很形象: 使用棧就象我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。 使用堆就象是自己動手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。

3,GC和堆棧、堆 由前述堆棧和堆的概念可以看出,堆棧不存在垃圾收集的問題,只需要直接壓棧即可,而堆,則面臨著很複雜的記憶體回收的問題。GC完全是對堆進行操作的,而對堆中對象是否有效判斷則是通過遍曆堆棧來實現的。這裡涉及到一個引用計數的概念,引用計數是對堆中對象被引用次數的統計,當一個對象的引用計數為零了,那麼這個對象就可以被回收了。在進行GC的時候,記憶體回收行程遍曆堆棧,當發現一個堆地址的時候,它就將堆中該地址上的對象的引用計數加1,然後銷毀堆中所有引用計數為零的對象,回收記憶體並整理堆中的片段。

4,類執行個體化的步驟 類是最常見也是我們用的最多的一種參考型別,我們知道執行個體化一個類使用的是一個我們司空見慣的語句: ClassA ca = new ClassA(); 那麼這短短的一句話中,電腦又做了些什麼事情呢? 實際上,電腦在這個過程中大致做了這麼幾件事: 首先,在ClassA ca的時候,產生一個空的引用指標,並將它推入堆棧中: 然後,在new ClassA()的時候,產生ClassA的新的執行個體,並放入堆中: 在賦值號=這一步,將ca的引用指標指向剛剛產生的新執行個體: 這個時候,才算完成了整條語句的操作。

5,特例:string 類型與堆 大家知道,string類型是一種參考型別。但它又有一些實值型別的特徵。比如指向同一個字串的兩個string變數,如果其中一個變數值發生了改變,卻不會影響到另外一個string變數。這就是因為: (1)CLR使用了一種叫字串駐留的技術,對於 string   str1="abc"; string   str2="abc"; 當CLR初始化時,會建立一個內部的散列表,其中的鍵為字串,值為指向託管堆中字串的引用。剛開始,散列表為空白,JIT編譯器編譯方法時,會在散列表中尋找每一個文本常量字串,首先會尋找"abc"字串,並且因為沒有找到,編譯器會在託管堆中構造一個新的指向"abc"的String對象引用,然後將"abc"字串和指向該對象的引用添加到散列表中。   接著,在散列表中尋找第二個"abc",這一次由於找到了該字串,所以編譯器不會執行任何操作,代碼中再沒有其它的文本常量字串,編譯器的任務完成,代碼開始執行。執行時,CLR發現第一個語句需要一個"abc"字串引用,於是,CLR會在內部的散列表中尋找"abc",並且會找到,這樣指向先前建立的String對象的引用就被儲存在變數s1中,執行第二條語句時,CLR會再一次在散列表中尋找"abc",並且仍然會找到,指向同一個String對象的引用會被儲存在變數s2中,到此s1和s2指向了同一個引用,所以System.Object.Equals(s1,s2)就會返回true了。 (2)當使用重載操作符”=”給string對象賦值時,string的對象是參考型別,它保留在堆上,而不是堆棧上.因此,當把一個字串賦給另一個字串時,會得到對記憶體中同一個字串的兩個引用.例如,修改其中一個字串,就會建立一個全新的string對象(注意,這個過程發生在”=”中),而另一個字串沒有改變.
6,C#中實值型別分配在堆棧中。 實值型別:bool,byte,char,decimal,double,enum,float,int,long,sbyte,short,struct,uint,ulong,ushort. 7,C#中參考型別分配在堆中,在堆棧中建立一個指向到堆的引用,返回給聲明的變數。 參考型別:class,delegate,interface,object,string
備忘:1. 實值型別數組雖然分配在堆上,但數組元素依然是實值型別,並沒有被裝箱。         2, 引用對象的實值型別成員也隨對象一起分配在堆上,同樣也還是實值型別,沒有被裝箱

1,什麼是GC GC的全稱是garbage collection,中文名稱記憶體回收,是.net中對記憶體管理的一種功能。記憶體回收行程跟蹤並回收託管記憶體中分配的對象,定期執行記憶體回收以回收分配給沒有有效引用的對象的記憶體。當使用可用記憶體不能滿足記憶體請求時,GC會自動進行。在進行記憶體回收時,記憶體回收行程回首先搜尋記憶體中的託管對象,然後從Managed 程式碼中搜尋被引用的對象並標記為有效,接著釋放沒有被標記為有效對象並收回記憶體,最後整理記憶體將有效對象挪動到一起。這就是GC的四個步驟。 由上可見,GC是很影響效能的,所以一般說來這種事情況還是盡量少發生為好。 為了減少一些效能影響,.net的GC支援對象老化,或者說分代的概念,代是對象在記憶體中相對存現時期的度量單位,對象的代數或存現時期說明對象所屬的代。目前.net的記憶體回收行程支援三代。每進行一次GC,沒有被回收的對象就自動提升一代。較近建立的對象屬於較新的代,比在應用程式生命週期中較早建立的對象的代數低。最近代中的對象位於零代中。每一次GC的時候,都首先回收零代中的對象,只有在較低代數的對象回收完成後仍不能滿足需求的情況下才回收較高代數的對象。

2,讀文章,看到了一個關於堆和棧(堆棧)的區別的比喻。很形象: 使用棧就象我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。 使用堆就象是自己動手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。

3,GC和堆棧、堆 由前述堆棧和堆的概念可以看出,堆棧不存在垃圾收集的問題,只需要直接壓棧即可,而堆,則面臨著很複雜的記憶體回收的問題。GC完全是對堆進行操作的,而對堆中對象是否有效判斷則是通過遍曆堆棧來實現的。這裡涉及到一個引用計數的概念,引用計數是對堆中對象被引用次數的統計,當一個對象的引用計數為零了,那麼這個對象就可以被回收了。在進行GC的時候,記憶體回收行程遍曆堆棧,當發現一個堆地址的時候,它就將堆中該地址上的對象的引用計數加1,然後銷毀堆中所有引用計數為零的對象,回收記憶體並整理堆中的片段。

4,類執行個體化的步驟 類是最常見也是我們用的最多的一種參考型別,我們知道執行個體化一個類使用的是一個我們司空見慣的語句: ClassA ca = new ClassA(); 那麼這短短的一句話中,電腦又做了些什麼事情呢? 實際上,電腦在這個過程中大致做了這麼幾件事: 首先,在ClassA ca的時候,產生一個空的引用指標,並將它推入堆棧中: 然後,在new ClassA()的時候,產生ClassA的新的執行個體,並放入堆中: 在賦值號=這一步,將ca的引用指標指向剛剛產生的新執行個體: 這個時候,才算完成了整條語句的操作。

5,特例:string 類型與堆 大家知道,string類型是一種參考型別。但它又有一些實值型別的特徵。比如指向同一個字串的兩個string變數,如果其中一個變數值發生了改變,卻不會影響到另外一個string變數。這就是因為: (1)CLR使用了一種叫字串駐留的技術,對於 string   str1="abc"; string   str2="abc"; 當CLR初始化時,會建立一個內部的散列表,其中的鍵為字串,值為指向託管堆中字串的引用。剛開始,散列表為空白,JIT編譯器編譯方法時,會在散列表中尋找每一個文本常量字串,首先會尋找"abc"字串,並且因為沒有找到,編譯器會在託管堆中構造一個新的指向"abc"的String對象引用,然後將"abc"字串和指向該對象的引用添加到散列表中。   接著,在散列表中尋找第二個"abc",這一次由於找到了該字串,所以編譯器不會執行任何操作,代碼中再沒有其它的文本常量字串,編譯器的任務完成,代碼開始執行。執行時,CLR發現第一個語句需要一個"abc"字串引用,於是,CLR會在內部的散列表中尋找"abc",並且會找到,這樣指向先前建立的String對象的引用就被儲存在變數s1中,執行第二條語句時,CLR會再一次在散列表中尋找"abc",並且仍然會找到,指向同一個String對象的引用會被儲存在變數s2中,到此s1和s2指向了同一個引用,所以System.Object.Equals(s1,s2)就會返回true了。 (2)當使用重載操作符”=”給string對象賦值時,string的對象是參考型別,它保留在堆上,而不是堆棧上.因此,當把一個字串賦給另一個字串時,會得到對記憶體中同一個字串的兩個引用.例如,修改其中一個字串,就會建立一個全新的string對象(注意,這個過程發生在”=”中),而另一個字串沒有改變.
6,C#中實值型別分配在堆棧中。 實值型別:bool,byte,char,decimal,double,enum,float,int,long,sbyte,short,struct,uint,ulong,ushort. 7,C#中參考型別分配在堆中,在堆棧中建立一個指向到堆的引用,返回給聲明的變數。 參考型別:class,delegate,interface,object,string
備忘:1. 實值型別數組雖然分配在堆上,但數組元素依然是實值型別,並沒有被裝箱。         2, 引用對象的實值型別成員也隨對象一起分配在堆上,同樣也還是實值型別,沒有被裝箱

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.