堆 棧 值型別 引用型別 裝箱 拆箱

2021-09-04 13:22:32 字數 2985 閱讀 8335

一來是為了感受國外優秀技術社群知名博主的高質量文章,二來是為了複習對.net技術的基礎拾遺達到溫故知新的效果,最後也是為了鍛鍊一下自己的英文讀寫能力。因為是首次翻譯英文文章(哎,原諒我這個菜比,弱爆了!),所以肯定會有很多問題(有些語句理解不透徹,翻譯出來也不通順,還請不吝賜教),也請各位園友多多指正,謝謝!

本文會闡述六個重要的概念:堆、棧、值型別、引用型別、裝箱和拆箱。本文首先會通過闡述當你定義乙個變數之後系統內部發生的改變開始講解,然後將關注點轉移到儲存雙雄:堆和棧。之後,我們會**一下值型別和引用型別,並對有關於這兩種型別的重要基礎內容做乙個講解。

當你在乙個.net應用程式中定義乙個變數時,在ram中會為其分配一些記憶體塊。這塊記憶體有三樣東西:變數的名稱變數的資料型別以及變數的值

上面簡單闡述了記憶體中發生的事情,但是你的變數究竟會被分配到哪種型別的記憶體取決於資料型別。在.net中有兩種可分配的記憶體:。在接下來的幾個部分中,我們會試著詳細地來理解這兩種型別的儲存。

為了理解棧和堆,讓我們通過以下的**來了解背後到底發生了什麼。

public void method1()

**只有三行,現在我們可以一行一行地來了解到底內部是怎麼來執行的。

現在我們許多的開發者朋友一定很好奇為什麼會有兩種不同型別的儲存?我們為什麼不能將所有的記憶體塊分配只到一種型別的儲存上?

如果你觀察足夠仔細,基元資料型別並不複雜,他們僅僅儲存像 『int i = 0』這樣的值。物件資料型別就複雜了,他們引用其他物件或其他基元資料型別。換句話說,他們儲存其他多個值的引用並且這些值必須一一地儲存在記憶體中。物件型別需要的是動態記憶體而基元型別需要靜態記憶體。如果需求是動態記憶體的話,那麼它將會在堆上為其分配記憶體,相反,則會在棧上為其分配。

既然我們已經了解了棧和堆的概念了,是時候了解值型別和引用型別的概念了。值型別將資料和記憶體都儲存在同一位置,而乙個引用型別則會有乙個指向實際記憶體區域的指標。

通過下圖,我們可以看到乙個名為i的整形資料型別,它的值被賦值到另乙個名為j的整形資料型別。他們的值都被儲存到了棧上。

當我們將乙個int型別的值賦值到另乙個int型別的值時,它實際上是建立了乙個完全不同副本。換句話說,如果你改變了其中某乙個的值,另乙個不會發生改變。於是,這些種類的資料型別被稱為「值型別」。

當我們建立乙個物件並且將此物件賦值給另外乙個物件時,他們彼此都指向了如下圖**段所示的記憶體中同一塊區域。因此,當我們將obj賦值給obj1時,他們都指向了堆中的同一塊區域。換句話說,如果此時我們改變了其中任何乙個,另乙個都會受到影響,這也說明了他們為何被稱為「引用型別」。

在.net中,變數是儲存到棧還是堆中完全取決於其所屬的資料型別。比如:『string』或『object』屬於引用型別,而其他.net基元資料型別則會被分配到棧上。下圖則詳細地展示了在.net預置型別中,哪些是值型別,哪些又是引用型別。

現在,你已經有了不少的理論基礎了。現在,是時候了解上面的知識在實際程式設計中的使用了。在應用中最大的乙個意義就在於:理解資料從棧移動到堆的過程中所發生的效能消耗問題,反之亦然。

考慮一下以下的**片段,當我們將乙個值型別轉換為引用型別,資料將會從棧移動到堆中。相反,當我們將乙個引用型別轉換為值型別時,資料也會從堆移動到棧中。

不管是在從棧移動到堆還是從堆中移動到棧上都會不可避免地對系統效能產生一些影響。

於是,兩個新名詞橫空出世:當資料從值型別轉換為引用型別的過程被稱為「裝箱」,而從引用型別轉換為值型別的過程則被成為「拆箱」。

如果你編譯一下上面這段**並且在ildasm(乙個il的反編譯工具)中對其進行檢視,你會發現在il**中,裝箱和拆箱是什麼樣子的。下圖則展示了示例**被編譯後所產生的il**。

為了弄明白到底裝箱和拆箱會帶來怎樣的效能影響,我們分別迴圈執行10000次下圖所示的兩個函式方法。其中第乙個方法中有裝箱操作,另乙個則沒有。我們使用乙個stopwatch物件來監視時間的消耗。

具有裝箱操作的方法花費了3542毫秒來執行完成,而沒有裝箱操作的方法只花費了2477毫秒,整整相差了1秒多。而且,這個值也會因為迴圈次數的增加而增加。也就是說,我們要盡量避免裝箱和拆箱操作。在乙個專案中,如果你需要裝箱和裝箱,請仔細考慮它是否是絕對必不可少的操作,如果不是,那麼盡量不用。

雖然以上**段沒有展示拆箱操作,但其效果同樣適用於拆箱。你可以通過寫**來實現拆箱,並且通過stopwatch來測試其時間消耗。

值型別 引用型別,裝箱 拆箱

值型別 宣告乙個值型別變數,會在棧上分配乙個空間,空間裡儲存的就是變數的值 引用型別 宣告乙個引用型別變數,會在棧中分配乙個空間,儲存乙個引用,這個引用指向了乙個託管堆。值型別 struct,列舉,數值型別,bool型別 引用型別 陣列,類,介面,委託 delegate object,string ...

值型別和引用型別,裝箱和拆箱

c 中任何型別都是隱式繼承自 system.object 引用型別 分為兩大類,值型別和引用型別。值型別包括 簡單型別 int,float,double等 結構體,列舉 引用型別包括 自定義的類,字串,介面,陣列 區別 1.值型別儲存在棧中,自動釋放,比較高效 引用型別儲存在堆中,需要手動釋放 2....

值型別與引用型別區別and裝箱與拆箱

1.引用型別的內存在託管堆上分配的。new操作符會返回物件的記憶體位址。2.值型別比引用型別輕量級 值型別包含啥呢,結構和列舉 3.值型別是不能作為基類 4.gc不管值型別 5.引用型別沒有初始化時是null,即不指向任何的記憶體位址,如果使用會拋異常nullreference異常 值型別的初始值是...