最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談C#中堆和棧的區(qū)別(附上圖解)

 更新時(shí)間:2014年09月18日 09:01:35   投稿:hebedich  
C#中棧是編譯期間就分配好的內(nèi)存空間,因此你的代碼中必須就棧的大小有明確的定義;堆是程序運(yùn)行期間動(dòng)態(tài)分配的內(nèi)存空間,你可以根據(jù)程序的運(yùn)行情況確定要分配的堆內(nèi)存的大小

線程堆棧:簡(jiǎn)稱棧 Stack
托管堆: 簡(jiǎn)稱堆 Heap

使用.Net框架開發(fā)程序的時(shí)候,我們無(wú)需關(guān)心內(nèi)存分配問(wèn)題,因?yàn)橛蠫C這個(gè)大管家給我們料理一切。如果我們寫出如下兩段代碼:
代碼段1:

public int AddFive(int pValue)
{
int result;
result = pValue + 5;
return result;
}


代碼段2:

public class MyInt
{ 
public int MyValue;
}

public MyInt AddFive(int pValue)
{
MyInt result = new MyInt();
result.MyValue = pValue + 5;
return result;
}


問(wèn)題1:你知道代碼段1在執(zhí)行的時(shí)候,pValue和result在內(nèi)存中是如何存放,生命周期又如何?代碼段2呢?
要想釋疑以上問(wèn)題,我們就應(yīng)該對(duì).Net下的棧(Stack)和托管堆(Heap)(簡(jiǎn)稱堆)有個(gè)清楚認(rèn)識(shí),本立而道生。如果你想提高程序性能,理解棧和堆,必須的!
本文就從棧和堆,類型變量展開,對(duì)我們寫的程序進(jìn)行庖丁解牛。
C#程序在CLR上運(yùn)行的時(shí)候,內(nèi)存從邏輯上劃分兩大塊:棧,堆。這倆基本元素組成我們C#程序的運(yùn)行環(huán)境。

一,棧 vs 堆:區(qū)別?

棧通常保存著我們代碼執(zhí)行的步驟,如在代碼段1中 AddFive()方法,int pValue變量,int result變量等等。而堆上存放的則多是對(duì)象,數(shù)據(jù)等。(譯者注:忽略編譯器優(yōu)化)我們可以把棧想象成一個(gè)接著一個(gè)疊放在一起的盒子。當(dāng)我們使用的時(shí)候,每次從最頂部取走一個(gè)盒子。棧也是如此,當(dāng)一個(gè)方法(或類型)被調(diào)用完成的時(shí)候,就從棧頂取走(called a Frame,譯注:調(diào)用幀),接著下一個(gè)。堆則不然,像是一個(gè)倉(cāng)庫(kù),儲(chǔ)存著我們使用的各種對(duì)象等信息,跟棧不同的是他們被調(diào)用完畢不會(huì)立即被清理掉。

如圖1,棧與堆示意圖

(圖1)

棧內(nèi)存無(wú)需我們管理,也不受GC管理。當(dāng)棧頂元素使用完畢,立馬釋放。而堆則需要GC(Garbage collection:垃圾收集器)清理。


二,什么元素被分配到棧?什么被分配到堆?

當(dāng)我們程序執(zhí)行的時(shí)候,在棧和堆中分配有四種主要的類型:值類型,引用類型,指針,指令。

值類型:
在C#中,繼承自System.ValueType的類型被稱為值類型,主要有以下幾種(CLR2.0中支持類型有增加):
* bool
* byte
* char
* decimal
* double
* enum
* float
* int
* long
* sbyte
* short
* struct
* uint
* ulong
* ushort

引用類型:
以下是引用類型,繼承自System.Object:
* class
* interface
* delegate
* object
* string

指針:
在內(nèi)存區(qū)中,指向一個(gè)類型的引用,通常被稱為“指針”,它是受CLR( Common Language Runtime:公共語(yǔ)言運(yùn)行時(shí))管理,我們不能顯示使用。需要注意的是,一個(gè)類型的引用即指針跟引用類型是兩個(gè)完全不同的概念。指針在內(nèi)存中占一塊內(nèi)存區(qū),它本身只代表一個(gè)內(nèi)存地址(或者null),它所指向的另一塊內(nèi)存區(qū)才是我們真正的數(shù)據(jù)或者類型。如圖2:


(圖2)

指令:
后文對(duì)指令再做介紹。

三,如何分配?
我們先看一下兩個(gè)觀點(diǎn):
觀點(diǎn)1,引用類型總是被分配在堆上。(正確?)
觀點(diǎn)2,值類型和指針總是分配在被定義的地方,他們不一定被分配到棧上。(這個(gè)理解起來(lái)有點(diǎn)難度,需要慢慢來(lái))

上文提及的棧(Stack),在程序運(yùn)行的時(shí)候,每個(gè)線程(Thread)都會(huì)維護(hù)一個(gè)自己的專屬線程堆棧。
當(dāng)一個(gè)方法被調(diào)用的時(shí)候,主線程開始在所屬程序集的元數(shù)據(jù)中,查找被調(diào)用方法,然后通過(guò)JIT即時(shí)編譯并把結(jié)果(一般是本地CPU指令)放在棧頂。CPU通過(guò)總線從棧頂取指令,驅(qū)動(dòng)程序以執(zhí)行下去。

下面我們以實(shí)例來(lái)詳談。

還是我們開篇所列的代碼段1:

public int AddFive(int pValue)
{
int result;
result = pValue + 5;
return result;
}

當(dāng)AddFive方法開始執(zhí)行的時(shí)候,方法參數(shù)(parameters)則在棧上分配。如圖3:

(圖3)

注意:方法并不在棧中存活,圖示僅供參考。
接著,指令指向AddFive方法內(nèi)部,如果該方法是第一次執(zhí)行,首先要進(jìn)行JIT即時(shí)編譯。如圖4:


(圖4)

當(dāng)方法內(nèi)部開始執(zhí)行的時(shí)候,變量result被分配在棧上,如圖5:


(圖5)

方法執(zhí)行完畢,而且方法返回后,如圖6所示:

(圖6)

在方法執(zhí)行完畢返回后,棧上的區(qū)域被清理。如圖7:

(圖7)

以上看出,一個(gè)值類型變量,一般會(huì)分配在棧上。那觀點(diǎn)2中所述又做何理解?“值類型和指針總是分配在被定義的地方,他們不一定被分配到棧上”。
原因就是如果一個(gè)值類型被聲明在一個(gè)方法體外并且在一個(gè)引用類型中,那它就會(huì)在堆上進(jìn)行分配。
還是代碼段2:

public class MyInt
{ 
public int MyValue;
}

public MyInt AddFive(int pValue)
{
MyInt result = new MyInt();
result.MyValue = pValue + 5;
return result;
}

當(dāng)線程開始執(zhí)行AddFive方法的時(shí)候,參數(shù)被分配到棧上,如圖8所示:

(圖8)
由于MyInt是一個(gè)引用類型,所以它被分配到堆上,并且在棧中生成一個(gè)指針(result),如圖9:

(圖9)
AddFive方法執(zhí)行完畢時(shí)的情況如圖10:

(圖10)

棧上內(nèi)存被清理,堆中依然存在,如圖11:


(圖11)

當(dāng)程序需要更多的堆空間時(shí),GC需要進(jìn)行垃圾清理工作,暫停所有線程,找出所有不可達(dá)到對(duì)象,即無(wú)被引用的對(duì)象,進(jìn)行清理。并通知棧中的指針重新指向地址排序后的對(duì)象?,F(xiàn)在我們應(yīng)該知道,了解棧和堆,對(duì)我們開發(fā)出高性能程序的重要性。當(dāng)我們使用引用類型的時(shí)候,一般是對(duì)指針進(jìn)行的操作而非引用類型對(duì)象本身。但是值類型則操作其本身。
接下來(lái),我們用例子說(shuō)明這一點(diǎn)。

例1:

public int ReturnValue()
{
int x = new int();
x = 3;
int y = new int();
y = x; 
y = 4; 
return x;
}

執(zhí)行結(jié)果為3,稍作修改:

例2:

public class MyInt
{
public int MyValue;
}

public int ReturnValue2()
{
MyInt x = new MyInt();
x.MyValue = 3;
MyInt y = new MyInt();
y = x; 
y.MyValue = 4; 
return x.MyValue;
}

執(zhí)行結(jié)果為4。

我們來(lái)分析下原因,其實(shí)例1的跟以下代碼所起效用一樣:

public int ReturnValue()
{
int x = 3;
int y = x; 
y = 4;
return x;
}


如圖12所示,在棧上x和y分別占用一塊內(nèi)存區(qū),互不干擾。

(圖12)

而例2,與以下代碼所起效用一樣:

public int ReturnValue2()
{
MyInt x;
x.MyValue = 3;
MyInt y;
y = x; 
y.MyValue = 4;
return x.MyValue;
}

如圖13所示,


(圖13)
棧上的指針x和y指向堆上同一個(gè)區(qū)域,修改其一必會(huì)改變堆上的數(shù)據(jù)。

相關(guān)文章

  • Winform中實(shí)現(xiàn)圖片格式轉(zhuǎn)換

    Winform中實(shí)現(xiàn)圖片格式轉(zhuǎn)換

    這篇文章主要介紹了Winform中實(shí)現(xiàn)圖片格式轉(zhuǎn)換的示例代碼,幫助大家更好的理解和使用winform開發(fā),感興趣的朋友可以了解下
    2020-12-12
  • C#難點(diǎn)逐個(gè)擊破(3):params數(shù)組參數(shù)

    C#難點(diǎn)逐個(gè)擊破(3):params數(shù)組參數(shù)

    注意,這里的paras全稱是array parameter,也就是數(shù)組參數(shù)。 paras類型參數(shù)主要用于在對(duì)數(shù)組長(zhǎng)度未知(可變)的情況下進(jìn)行函數(shù)聲明。
    2010-02-02
  • C#實(shí)現(xiàn)JWT無(wú)狀態(tài)驗(yàn)證的實(shí)戰(zhàn)應(yīng)用解析

    C#實(shí)現(xiàn)JWT無(wú)狀態(tài)驗(yàn)證的實(shí)戰(zhàn)應(yīng)用解析

    這篇文章主要介紹了C#實(shí)現(xiàn)JWT無(wú)狀態(tài)驗(yàn)證的實(shí)戰(zhàn)應(yīng)用解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • 解決Unity無(wú)限滾動(dòng)復(fù)用列表的問(wèn)題

    解決Unity無(wú)限滾動(dòng)復(fù)用列表的問(wèn)題

    這篇文章主要介紹了Unity無(wú)限滾動(dòng)復(fù)用列表,無(wú)限滾動(dòng)復(fù)用ScrollView就是解決這種問(wèn)題,還可以用來(lái)做朋友圈,聊天等,需要的朋友可以參考下
    2022-04-04
  • C#獲取日期的星期名稱實(shí)例代碼

    C#獲取日期的星期名稱實(shí)例代碼

    本文通過(guò)實(shí)例代碼給大家介紹了基于c#獲取日期的星期名稱,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2018-08-08
  • c# 組合模式

    c# 組合模式

    組合模式:將對(duì)象組合成樹形結(jié)構(gòu)以表示‘部分-整體’的層次結(jié)構(gòu)。組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。需求中式體現(xiàn)部分與整體層次的結(jié)構(gòu)時(shí),統(tǒng)一地使用組合對(duì)象中的所有對(duì)象時(shí),應(yīng)該考慮使用組合模式
    2012-10-10
  • 常用.NET工具(包括.NET可再發(fā)行包2.0)下載

    常用.NET工具(包括.NET可再發(fā)行包2.0)下載

    常用.NET工具(包括.NET可再發(fā)行包2.0)下載...
    2007-03-03
  • C#實(shí)現(xiàn)將聊天數(shù)據(jù)發(fā)送加密

    C#實(shí)現(xiàn)將聊天數(shù)據(jù)發(fā)送加密

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)將聊天數(shù)據(jù)發(fā)送加密的功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • C#中調(diào)用VB中Inputbox類的實(shí)現(xiàn)方法

    C#中調(diào)用VB中Inputbox類的實(shí)現(xiàn)方法

    本文主要介紹在項(xiàng)目中引用Microsoft.VisualBasic,間接使用VB中的各種類庫(kù)的方法,或者自己創(chuàng)建函數(shù),調(diào)用自定義方法,以實(shí)現(xiàn)InputBox相關(guān)的功能。
    2016-05-05
  • 關(guān)于c#中枚舉類型支持顯示中文的擴(kuò)展說(shuō)明

    關(guān)于c#中枚舉類型支持顯示中文的擴(kuò)展說(shuō)明

    需求?。骸∶杜e類型在界面顯示的時(shí)候可以顯示相應(yīng)的中文信息, 這樣界面對(duì)用戶友好 . 場(chǎng)景 : 在一些業(yè)務(wù)中涉及到審核功能的時(shí)候, 往往有這幾個(gè)狀態(tài) :未送審 , 審核中 ,審核通過(guò), 駁回 . 這個(gè)時(shí)候我們會(huì)定義一個(gè)枚舉類型來(lái)描述?。?/div> 2013-03-03

最新評(píng)論

海晏县| 老河口市| 武汉市| 博湖县| 房山区| 通河县| 长宁区| 佛教| 西昌市| 蓬莱市| 双鸭山市| 宿迁市| 鄄城县| 宣武区| 泸溪县| 徐汇区| 巫溪县| 怀集县| 苏尼特右旗| 屏南县| 宜兰市| 广饶县| 锡林浩特市| 苏尼特右旗| 易门县| 大庆市| 泸西县| 顺昌县| 安康市| 泽普县| 安新县| 启东市| 会同县| 永川市| 宁晋县| 南宁市| 咸阳市| 思茅市| 馆陶县| 西藏| 张家口市|