C# 堆VS棧 值類型VS引用類型


最近博客園上連續出現了幾篇關於堆VS棧 值類型VS引用類型的文章。

 

一個是關於C# 堆VS棧的,深入淺出,動圖清晰明了,鏈接如下

C#堆棧對比(Part One)

C#堆棧對比(Part Two)

C#堆棧對比(Part Three)

C#堆棧對比(Part Four)

二是從Eric Lippert(Eric Lippert is a principal developer on the C# compiler team)的文章演變出的兩篇,鏈接如下

The Truth About Value Types

你真的了解C#中的值和引用嗎?(上)

匹夫細說C#:不是“棧類型”的值類型,從生命周期聊存儲位置

 

下面是我的思考和總結,希望能與大家分享和討論。

值類型和引用類型的區別

最近和同事一起面試時也經常問這個問題,被面的同學很多回答為“值類型存儲在棧里,引用類型存儲在堆里”,首先我們先不去深究這個說法是否准確(上面的文章里已經說的很清楚)。

值類型和引用類型的區別是存儲位置的不同嗎

Eric Lippert給出的答案----值類型和引用類型的區別在語義層面,與存儲位置無關。存儲位置是C#編譯運行時的分配,是實現細節。

  或許C# compiler的未來版本中,值類型也可能不存儲在棧里;

  或者某一個系統平台中並不存在堆和棧的概念。

結論

  “值類型和引用類型的區別,與存儲位置無關”。

 

值類型和引用類型區別是什么呢?

Eric Lippert說 - 值類型和引用類型的區別在語義層面。要怎么理解?我們思考的視角應該是C#語言語義和使用上。

結論

  “值類型傳遞的是值(不同的實例,互不影響),引用類型傳遞的是引用(同一個實例,互相影響)

    如同一句廢話!那我們試着換幾種方式來描述(可能不准確

    1. 值類型是私有的,是持有者自己的東西;引用類型是共享的,大家共有的東西。

    2. 值類型是多實例的,每次傳遞都創建新實例;引用類型是單實例的,每次傳遞都是同一個實例,如設計模式中的單例。

    3. 值類型的生命周期和持有者相同;引用類型的生命周期和持有者不同。(有關生命周期的言論)

 

為什么在討論值類型和引用類型時,總會出現堆和棧?

如何實現值類型和引用類型的存儲?

  有兩種存儲方式可供選擇

    一 直接存儲的優點是性能高,缺點是共享不方便。(棧或者堆上

    二 間接存儲的優點是共享方便,缺點是多了一次跳轉,有性能損失。(堆上

 

我們要的關注哪些問題?性能,共享方式(生命周期)

  值類型是不共享的,它的生命周期和持有者相同,所以可以直接存儲,如果間接存儲,會多一次跳轉,沒有意義的性能損失。

  引用類型是共享的,它的生命周期和持有者不同,所以采用間接存儲,如果直接存儲,是很難實現共享和生命周期的不同。

結論

  值類型是直接存儲,引用類型是間接存儲。是基於實現的考量,不是值類型和引用類型的區別。

  生命周期是從實現角度思考的推論,也不是值類型和引用類型的區別。

 

為什么存在兩種類型(值類型和引用類型),而不僅僅是一種類型(值類型或者引用類型)?

思考后發現,所有值類型都可以被引用類型所替代,那為什么要有值類型呢?沒有得出理想的答案,推測有兩種可能

  一 歷史傳承。

  二 基於性能的考量。這個應該是實現級別的事情,為什么被暴露在語言級別上?沒有辦法解決嗎?(對於值來說,引用類型多了一次跳轉;對於引用來說,值的傳遞多了一次深克隆)

 

何時用值類型(struct),何時用引用類型(class)?

在工作中很少(幾乎沒有)使用struct,因為性能上的收益遠遠無法彌補維護成本的損失

(不能要求每個開發人員都很了解struct和class的不同,並在修改代碼時意識到使用的是struct而不是class)

 

總結

值和引用類型的區別是語言和使用級別的

值類型傳遞的是值(不同的實例,互不影響),引用類型傳遞的是引用(同一個實例,互相影響)

有關值類型和引用類型儲存在棧或者堆上的言論,是基於實現細節的思考,是當前的實現方式,不是值類型和引用類型的區別。

有關值類型和引用類型生命周期的言論,是基於實現細節的思考,是當前的實現方式,不是值類型和引用類型的區別。

值類型(struct)更多是性能上的收益,C#中定義的基礎值類型已經足夠,開發中盡量避免定義值類型(struct)

 

期待看到不同的觀點和理由!

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM