六、內(nèi)存剖析

C#將數(shù)據(jù)分為兩種:值數(shù)據(jù)類型和引用數(shù)據(jù)類型唯欣,這兩種數(shù)據(jù)類型存儲在內(nèi)存中的不同的地方:值數(shù)據(jù)類型存儲在棧中,而引用類型存儲在內(nèi)存的托管堆中搬味。

  • 1境氢、內(nèi)存簡介
    Windows使用一個系統(tǒng):虛擬尋址系統(tǒng)。這個系統(tǒng)的作用是將程序可用的內(nèi)存地址映射到硬件內(nèi)存中的實際地址上碰纬。其實際結(jié)果就是32位的機(jī)子上每個進(jìn)程都可以使用4GB的內(nèi)存萍聊,當(dāng)然,64位機(jī)這個數(shù)字就大了去了悦析。這4GB的內(nèi)存實際上包含了程序的所有的部分:可執(zhí)行代碼寿桨,DLL以及程序運(yùn)行時使用的所有變量的內(nèi)容。這個4GB的內(nèi)存成為虛擬地址空間或虛擬內(nèi)存强戴。為方便亭螟,這里成為內(nèi)存。
    4GB中的每個存儲單元都是從零開始向上存儲的酌泰。要訪問存儲在內(nèi)存中的某個空間中的值媒佣,就必須提供表示該存儲單元的一個數(shù)字匕累。在高級編程語言中陵刹,編譯器的一個重要作用就是負(fù)責(zé)將人們可以理解的變量名稱變?yōu)樘幚砥骺梢岳斫獾膬?nèi)存地址。

  • 2、棧
    在內(nèi)存中衰琐,有一個區(qū)域成為棧也糊,存儲對象
    對象成員的值數(shù)據(jù)類型調(diào)用方法時,傳遞給所有方法的參數(shù)的副本注意:調(diào)用方法時羡宙,堆棧存儲的是所有參數(shù)的副本狸剃,因此,經(jīng)值類型A傳遞給函數(shù)狗热,A的值是不會變化的钞馁。當(dāng)然,引用類型是會變化的匿刮,因為在棧中存儲的是引用類型的地址僧凰,這在后面會有詳細(xì)的介紹。
    下面以一個例子來說明棧的工作方式熟丸,如下面的代碼:
    {
    int a;
    //do something;
    {
    int b;
    //do something
    }
    }
    首先聲明a训措,在內(nèi)部的代碼塊中聲明b,然后內(nèi)部的代碼塊終止光羞,b就出了作用域绩鸣,最后a出作用域。所以b的生命周期總是包含在a的生命周期內(nèi)纱兑,在釋放變量的時候呀闻,其順序總是和分配內(nèi)存的順序是相反的。即:變量的生存周期都是嵌套的潜慎。這就是棧的工作方式总珠。

  • 3、托管堆
    堆棧具有相當(dāng)高的性能勘纯,但是變量的生命周期必須是嵌套的局服,這個要求在有的時候過于苛刻。我們希望有一種別的方法來分配內(nèi)存驳遵,存儲一些數(shù)據(jù)淫奔,并在方法退出的很長一段時間內(nèi),這些數(shù)據(jù)仍然是可用的堤结,這時唆迁,就使用托管堆。
    托管堆(簡稱堆)是內(nèi)存中的另外一個區(qū)域竞穷,我們?nèi)匀挥靡粋€例子來說明堆的工作方式唐责,如下面代碼:
    {
    Customer customer1;
    customer1=new Customer();
    Customer customer2=new Customer();
    //do something
    }
    首先,聲明一個Customer:customer1瘾带,在棧上給這個引用分配存儲控件鼠哥。請注意:僅僅是給這個引用分配存儲空間,并不是實際的Customer對象。customer1占用4個字節(jié)的空間(32位機(jī))朴恳,來表示Customer對象在內(nèi)存中的地址抄罕。
    然后,執(zhí)行第二行代碼于颖,完成以下操作:
    在堆上分配存儲空間呆贿,用來存儲Customer對象,注意:這里是Customer對像森渐。
    將變量customer1的值設(shè)為分配給Customer對象的內(nèi)存地址從這個例子中可以看出做入,建立引用類型的變量的過程要比獎勵值類型變量的過程復(fù)雜,且不避免的有性能的降低同衣。但是母蛛,我們可以將一個引用變量的值賦給另一個引用變量,當(dāng)一個變量出作用域時乳怎,它會從棧中刪除彩郊,但是對象的數(shù)據(jù)仍然保留在內(nèi)存中,直到程序停止蚪缀。
    這樣秫逝,我們在將一個引用變量A傳遞給函數(shù)時,僅僅是將變量A的引用傳遞給了函數(shù)询枚,即:僅僅是在棧上分配內(nèi)存违帆,即變量B兩者指向同一個內(nèi)存地址。因此金蜀,當(dāng)變量B發(fā)生變化時刷后,變量A也會發(fā)生變化。

  • 4渊抄、裝箱和拆箱
    裝箱和拆箱就是值類型和引用類型的項目轉(zhuǎn)化尝胆,裝箱可以將值類型轉(zhuǎn)化為引用類型,拆箱的作用正好相反护桦,將引用類型轉(zhuǎn)化為值類型含衔。

  • 5、垃圾收集
    一般情況下二庵。NET運(yùn)行庫會在認(rèn)為需要的時候運(yùn)行垃圾收集器來釋放托管資源贪染,這在大多數(shù)情況下,足夠了催享。就是說我們沒有必要去關(guān)心內(nèi)存杭隙。但在有的情況下,我們會強(qiáng)制垃圾回收集器在代碼的某個地方運(yùn)行因妙,釋放內(nèi)存痰憎。這就用到了System.GC.Collect()票髓。System.GC表示一個垃圾收集器。這種情況很少信殊,例如:代碼中大量的對象剛剛停止引用炬称,就適合調(diào)用垃圾收集器汁果。

  • 6總結(jié)
    首先堆棧和堆(托管堆)都在進(jìn)程的虛擬內(nèi)存中涡拘。(在32位處理器上每個進(jìn)程的虛擬內(nèi)存為4GB)

    • 棧stack
      棧中存儲值類型。
      棧實際上是向下填充据德,即由高內(nèi)存地址指向低內(nèi)存地址填充鳄乏。
      棧的工作方式是先分配內(nèi)存的變量后釋放(先進(jìn)后出原則)。
      棧中的變量是從下向上釋放棘利,這樣就保證了棧中先進(jìn)后出的規(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運(yùn)行庫在堆中搜索第一個從未使用的,32字節(jié)的連續(xù)塊存儲Customer對象的實例寻馏!
      然后把分配給Customer對象實例的地址賦給cus變量棋弥!
      從這個例子中可以看出,建立對象引用的過程比建立值變量的過程復(fù)雜诚欠,且不能避免性能的降低顽染!
      實際上就是.NET運(yùn)行庫保存對的狀態(tài)信息漾岳,在堆中添加新數(shù)據(jù)時,棧中的引用變量也要更新粉寞。
      性能上損失很多尼荆!
      有種機(jī)制在分配變量內(nèi)存的時候,不會受到棧的限制:把一個引用變量的值賦給一個相同類型的變量唧垦,那么這兩個變量就引用同一個堆中的對象捅儒。
      當(dāng)一個應(yīng)用變量出作用域時,它會從棧中刪除振亮。但引用對象的數(shù)據(jù)仍然保留在堆中巧还,一直到程序結(jié)束或者該數(shù)據(jù)不被任何變量應(yīng)用時,垃圾收集器會刪除它坊秸。

  • 7麸祷、變量的內(nèi)存分析
    數(shù)據(jù)存儲是以“字節(jié)”(Byte)為單位,數(shù)據(jù)傳輸是以大多是以“位”(bit褒搔,又名“比特”)為單位阶牍,一個位就代表一個0或1(即[二進(jìn)制],每8個位(bit星瘾,簡寫為b)組成一個字節(jié)(Byte走孽,簡寫為B),字節(jié)是最小一級的信息單位死相。不同數(shù)據(jù)類型占據(jù)的字節(jié)不一樣融求。
    sizeof() 用于獲取非托管類型的大小(以字節(jié)為單位)算撮。 非托管類型包括下表列出的內(nèi)置類型以及以下類型:
    枚舉類型
    指針類型
    用戶定義的結(jié)構(gòu)生宛,不包含任何屬于引用類型的字段或?qū)傩?/p>

用法示例:

 static void Main(string[] args)
        {
               char c = '1';
               Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(c));
               Console.ReadKey();
        }

Console.WriteLine(System.Runtime.InteropServices.Marshal.SizeOf(short));獲取各數(shù)據(jù)類型所占得字節(jié)

C#中的各類型占據(jù)內(nèi)存容量:
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市肮柜,隨后出現(xiàn)的幾起案子陷舅,更是在濱河造成了極大的恐慌,老刑警劉巖审洞,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件莱睁,死亡現(xiàn)場離奇詭異,居然都是意外死亡芒澜,警方通過查閱死者的電腦和手機(jī)仰剿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來痴晦,“玉大人南吮,你說我怎么就攤上這事√茏茫” “怎么了部凑?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵帮碰,是天一觀的道長例驹。 經(jīng)常有香客問我懦胞,道長侍芝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任比勉,我火速辦了婚禮劳较,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘敷搪。我一直安慰自己兴想,他們只是感情好幢哨,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布赡勘。 她就那樣靜靜地躺著,像睡著了一般捞镰。 火紅的嫁衣襯著肌膚如雪闸与。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天岸售,我揣著相機(jī)與錄音践樱,去河邊找鬼。 笑死凸丸,一個胖子當(dāng)著我的面吹牛拷邢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播屎慢,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼瞭稼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腻惠?” 一聲冷哼從身側(cè)響起环肘,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎集灌,沒想到半個月后悔雹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡欣喧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年腌零,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唆阿。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡益涧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酷鸦,到底是詐尸還是另有隱情饰躲,我是刑警寧澤牙咏,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站嘹裂,受9級特大地震影響妄壶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜寄狼,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一丁寄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泊愧,春花似錦伊磺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至痰滋,卻和暖如春摘能,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背敲街。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工团搞, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人多艇。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓逻恐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親峻黍。 傳聞我的和親對象是個殘疾皇子复隆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容