最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

第 25 講:指針(二):棧內(nèi)存和堆內(nèi)存

2021-04-09 11:00 作者:SunnieShine  | 我要投稿

為了能學(xué)習(xí)后面的知識(shí)點(diǎn),我們先需要掌握棧內(nèi)存和堆內(nèi)存的基本概念。

本節(jié)沒(méi)有代碼,所以純理論的東西都很枯燥。如果你想要了解它們,那么只能慢慢學(xué)。

Part 1 簡(jiǎn)述

在 C# 程序里,有兩個(gè)主要的內(nèi)存區(qū)域,可以臨時(shí)提供和存儲(chǔ)數(shù)據(jù)的內(nèi)存空間。內(nèi)存空間存儲(chǔ)這些數(shù)據(jù)是為了在程序執(zhí)行的時(shí)候反復(fù)使用它們。如果不存儲(chǔ)的話,每一次數(shù)據(jù)都需要從外界讀取,然后使用一次就讀取一次。一來(lái)是速度慢,二來(lái)是不符合程序設(shè)計(jì)的靈活性。

為了保證數(shù)據(jù)處理的靈活性,C# 存儲(chǔ)數(shù)據(jù)的最重要的兩處數(shù)據(jù)存儲(chǔ)空間就有棧內(nèi)存(Stack Memory)和堆內(nèi)存(Heap Memory)。棧內(nèi)存用來(lái)執(zhí)行方法的過(guò)程的時(shí)候,存儲(chǔ)方法執(zhí)行期間的臨時(shí)變量啊這些數(shù)據(jù)信息;而堆內(nèi)存則是存儲(chǔ)很復(fù)雜的數(shù)據(jù)信息。在 C# 里,數(shù)組在執(zhí)行 new 語(yǔ)句后,就被放在了堆內(nèi)存里;而臨時(shí)變量(比如 int a = 3;a 作為臨時(shí)變量,就在棧內(nèi)存里存儲(chǔ)。

Part 2 棧內(nèi)存和堆內(nèi)存的區(qū)別

它們的作用都是存儲(chǔ)數(shù)據(jù)信息,用于計(jì)算。從存儲(chǔ)的角度來(lái)說(shuō),它們是沒(méi)有區(qū)別的;但是從內(nèi)存分配和內(nèi)存大小來(lái)說(shuō),就有區(qū)別了。

你可以試著認(rèn)為堆內(nèi)存是實(shí)驗(yàn)樓,而棧內(nèi)存就是教學(xué)樓。如果拿出一個(gè)具體的例子來(lái)說(shuō)明的話,你可以這么去理解:在體育活動(dòng)(程序運(yùn)行)期間,學(xué)生肯定需要進(jìn)入操場(chǎng)(運(yùn)算器)里參與活動(dòng)(進(jìn)行運(yùn)算)。但是,教學(xué)樓(棧內(nèi)存)往往相較于實(shí)驗(yàn)樓(堆內(nèi)存)距離操場(chǎng)(運(yùn)算器)要更近一些,因此會(huì)更快到達(dá)操場(chǎng)參與體育活動(dòng)(運(yùn)算)。而實(shí)驗(yàn)樓可以存儲(chǔ)很多儀器設(shè)備(內(nèi)存空間很大),但教學(xué)樓只能容納學(xué)生學(xué)習(xí)(方法調(diào)用),其它都不行,因此,教學(xué)樓(棧內(nèi)存)空間可能會(huì)比實(shí)驗(yàn)樓(堆內(nèi)存)空間要小。

棧內(nèi)存相較于堆內(nèi)存來(lái)說(shuō),執(zhí)行速度會(huì)更快一些;相反堆內(nèi)存里存取數(shù)據(jù)要慢一點(diǎn)。但就存儲(chǔ)空間來(lái)說(shuō),由于棧內(nèi)存執(zhí)行效率比堆內(nèi)存要高,因此不可能讓所有數(shù)據(jù)都丟進(jìn)棧內(nèi)存,這樣會(huì)把棧內(nèi)存空間撐爆,導(dǎo)致很嚴(yán)重的內(nèi)存溢出的問(wèn)題。因此,像是數(shù)組這類可以存儲(chǔ)較多數(shù)據(jù)的東西,也確實(shí)只能放在堆內(nèi)存里;相反,像是 int 啊、double 類型的這些臨時(shí)變量,不管你初始化多少個(gè),因?yàn)槭菃为?dú)的一個(gè)變量的初始化過(guò)程,因此都是被 C# 放在了棧內(nèi)存里。

所以:

  • 堆內(nèi)存空間更大,但效率更低;

  • 棧內(nèi)存空間較?。▋H用來(lái)提供臨時(shí)變量的存儲(chǔ)),但效率高。

Part 3 能否將臨時(shí)變量丟入堆內(nèi)存,或者把數(shù)組丟入棧內(nèi)存?

這是一個(gè)好問(wèn)題。C# 按照語(yǔ)法規(guī)則規(guī)定,內(nèi)置的類型被分成值類型(Value Type)和引用類型(Reference Type)兩種。值類型就是 int、double 這類基本數(shù)據(jù)分類的類型。這些類型在寫(xiě)成臨時(shí)變量的時(shí)候,只存儲(chǔ)在棧內(nèi)存里;而引用類型則是 string 和數(shù)組這類型的東西。它們往往不定長(zhǎng),隨著數(shù)據(jù)的變化而產(chǎn)生不同的存儲(chǔ)大小,因此它們可能會(huì)很大,因而在定義它們的臨時(shí)變量的時(shí)候,它們是存儲(chǔ)在堆內(nèi)存里的。

而目前的語(yǔ)法來(lái)說(shuō),就算是 string 很短,我們也不能丟進(jìn)棧內(nèi)存;相反,我們也不能把 int、double 這類型的東西丟入堆內(nèi)存里。語(yǔ)法是做不到的,而這個(gè)規(guī)定是 C# 語(yǔ)法本身的規(guī)則,所以你無(wú)法修改。但是,以后我們會(huì)慢慢學(xué)習(xí)到新的內(nèi)存,比如類類型、比如結(jié)構(gòu)類型。在說(shuō)到這些東西之后,我們就可以明白了,其實(shí)我們是可以通過(guò)別的方式來(lái)實(shí)現(xiàn)值類型丟進(jìn)堆內(nèi)存,或者引用類型丟進(jìn)棧內(nèi)存的問(wèn)題的。

Part 4 垃圾回收器

堆內(nèi)存和棧內(nèi)存還有一大區(qū)別是,使用完畢后,內(nèi)存空間里面的數(shù)據(jù)的去向。就像是紅細(xì)胞從出現(xiàn)到凋亡的整個(gè)過(guò)程,C# 規(guī)劃了一個(gè)模型來(lái)收集這些廢棄的東西。堆內(nèi)存里的數(shù)據(jù)一旦分配后,數(shù)據(jù)就一直存儲(chǔ)起來(lái)。但實(shí)際上,如果我們不去使用它們的話,這個(gè)變量也會(huì)一直存儲(chǔ)在那里;但相反的是,棧內(nèi)存的空間一旦在某個(gè)方法執(zhí)行完畢后,空間里面的數(shù)據(jù)就自動(dòng)隨著這個(gè)方法自動(dòng)銷毀掉。這個(gè)行為是自動(dòng)的。

但是,既然堆內(nèi)存的數(shù)據(jù)一直都放在那里的話,那么我們不斷去聲明需要堆內(nèi)存存儲(chǔ)的變量的話,內(nèi)存空間占用就會(huì)越來(lái)越大,最終撐爆內(nèi)存。因此,當(dāng)某個(gè)時(shí)候發(fā)現(xiàn)變量已經(jīng)不可能使用到了的話,C# 就會(huì)啟用垃圾回收器(Garbage Collector,簡(jiǎn)稱 GC),來(lái)全盤(pán)掃描用不上的堆內(nèi)存變量。換句話說(shuō),我們?cè)谧龉ぷ髯鋈蝿?wù)的時(shí)候,垃圾回收器就輔助我們?cè)谡也挥玫臇|西,將它們自動(dòng)處理掉。因?yàn)闂?nèi)存空間是自動(dòng)銷毀的,所以 GC(垃圾回收器,以后就寫(xiě)簡(jiǎn)寫(xiě)了)不會(huì)去在意棧內(nèi)存空間,它只關(guān)心堆內(nèi)存的變量。

比如我現(xiàn)在有 20 個(gè)堆內(nèi)存的變量。當(dāng)這些變量一旦不再使用后,GC 會(huì)按照它自己的節(jié)奏,開(kāi)始啟動(dòng)回收機(jī)制。將所有沒(méi)用到的變量自動(dòng)回收銷毀掉,并重新將變量的內(nèi)存空間按照次序重新擺放起來(lái)。因?yàn)槎褍?nèi)存的變量大小都不一定一樣大,因此,它可能是這樣的:

接著,假設(shè)變量 B、D 和 F 我們都不再使用了,GC 就會(huì)在某個(gè)時(shí)候開(kāi)始啟動(dòng)垃圾回收機(jī)制。將它們找出來(lái):

然后銷毀掉。銷毀之后,可以發(fā)現(xiàn),比如 C 和 E 之間縫隙太小。如果我們要安排別的變量存儲(chǔ)進(jìn)來(lái)的話,顯然是肯定不夠放的(因?yàn)榭赡芎苌儆袡C(jī)會(huì)創(chuàng)建占空間這么小的變量了),因此,GC 會(huì)進(jìn)行壓縮(Compact)處理,將這些小縫隙清除掉,把變量拼在一起:

可以發(fā)現(xiàn),一旦這么處理后,內(nèi)存存儲(chǔ)的地址必然會(huì)發(fā)現(xiàn)變動(dòng)。比如 A 變量可能沒(méi)有變動(dòng),但 C 的地址就會(huì)往前偏移一點(diǎn);同理,E 和 G 也是一樣的。因此,GC 會(huì)有這樣的一些隱式行為。希望我們注意。

另請(qǐng)注意,這種隱式行為是我們不學(xué)習(xí)這些知識(shí)點(diǎn)就一定不會(huì)知道的東西。但是后續(xù)的一些語(yǔ)法,就會(huì)用到它們才能理解,因此希望你注意。

總之:

  1. GC 只處理堆內(nèi)存空間;

  2. GC 按照自己的節(jié)奏,對(duì)堆內(nèi)存進(jìn)行處理。一旦發(fā)現(xiàn)某個(gè)變量以后都不會(huì)使用了的話,變量的內(nèi)存空間就會(huì)被 GC 自動(dòng)銷毀,并通過(guò)“緊湊”處理將銷毀后的變量空間消除掉,防止以后變量存儲(chǔ)過(guò)程之中無(wú)法利用到這些零散的小空間;

  3. GC 是 C# 里自帶的處理機(jī)制,因此你可以跟他打配合,但是你不能期望去改變它的處理行為。


第 25 講:指針(二):棧內(nèi)存和堆內(nèi)存的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
贞丰县| 云龙县| 石楼县| 雷波县| 长白| 亚东县| 册亨县| 资阳市| 大理市| 江北区| 贡觉县| 宜昌市| 上虞市| 顺平县| 汽车| 巴东县| 鲜城| 永新县| 礼泉县| 德安县| 巫溪县| 西藏| 乐安县| 桂林市| 娱乐| 溧水县| 吕梁市| 梅河口市| 扎兰屯市| 澜沧| 高州市| 沿河| 育儿| 尚义县| 婺源县| 于田县| 谷城县| 栖霞市| 方山县| 浙江省| 绩溪县|