C# 堆VS栈 值类型VS引用类型
最近博客园上连续出现了几篇关于堆VS栈 值类型VS引用类型的文章。
一个是关于C# 堆VS栈的,深入浅出,动图清晰明了,链接如下
二是从Eric Lippert(Eric Lippert is a principal developer on the C# compiler team)的文章演变出的两篇,链接如下
下面是我的思考和总结,希望能与大家分享和讨论。
值类型和引用类型的区别
最近和同事一起面试时也经常问这个问题,被面的同学很多回答为“值类型存储在栈里,引用类型存储在堆里”,首先我们先不去深究这个说法是否准确(上面的文章里已经说的很清楚)。
值类型和引用类型的区别是存储位置的不同吗?
Eric Lippert给出的答案----值类型和引用类型的区别在语义层面,与存储位置无关。存储位置是C#编译运行时的分配,是实现细节。
或许C# compiler的未来版本中,值类型也可能不存储在栈里;
或者某一个系统平台中并不存在堆和栈的概念。
结论
“值类型和引用类型的区别,与存储位置无关”。
值类型和引用类型区别是什么呢?
Eric Lippert说 - 值类型和引用类型的区别在语义层面。要怎么理解?我们思考的视角应该是C#语言语义和使用上。
结论
“值类型传递的是值(不同的实例,互不影响),引用类型传递的是引用(同一个实例,互相影响)”
如同一句废话!那我们试着换几种方式来描述(可能不准确)
1. 值类型是私有的,是持有者自己的东西;引用类型是共享的,大家共有的东西。
2. 值类型是多实例的,每次传递都创建新实例;引用类型是单实例的,每次传递都是同一个实例,如设计模式中的单例。
3. 值类型的生命周期和持有者相同;引用类型的生命周期和持有者不同。(有关生命周期的言论)
为什么在讨论值类型和引用类型时,总会出现堆和栈?
如何实现值类型和引用类型的存储?
有两种存储方式可供选择
一 直接存储的优点是性能高,缺点是共享不方便。(栈或者堆上)
二 间接存储的优点是共享方便,缺点是多了一次跳转,有性能损失。(堆上)
我们要的关注哪些问题?性能,共享方式(生命周期)
值类型是不共享的,它的生命周期和持有者相同,所以可以直接存储,如果间接存储,会多一次跳转,没有意义的性能损失。
引用类型是共享的,它的生命周期和持有者不同,所以采用间接存储,如果直接存储,是很难实现共享和生命周期的不同。
结论
值类型是直接存储,引用类型是间接存储。是基于实现的考量,不是值类型和引用类型的区别。
生命周期是从实现角度思考的推论,也不是值类型和引用类型的区别。
为什么存在两种类型(值类型和引用类型),而不仅仅是一种类型(值类型或者引用类型)?
思考后发现,所有值类型都可以被引用类型所替代,那为什么要有值类型呢?没有得出理想的答案,推测有两种可能
一 历史传承。
二 基于性能的考量。这个应该是实现级别的事情,为什么被暴露在语言级别上?没有办法解决吗?(对于值来说,引用类型多了一次跳转;对于引用来说,值的传递多了一次深克隆)
何时用值类型(struct),何时用引用类型(class)?
在工作中很少(几乎没有)使用struct,因为性能上的收益远远无法弥补维护成本的损失。
(不能要求每个开发人员都很了解struct和class的不同,并在修改代码时意识到使用的是struct而不是class)
总结
值和引用类型的区别是语言和使用级别的
值类型传递的是值(不同的实例,互不影响),引用类型传递的是引用(同一个实例,互相影响)
有关值类型和引用类型储存在栈或者堆上的言论,是基于实现细节的思考,是当前的实现方式,不是值类型和引用类型的区别。
有关值类型和引用类型生命周期的言论,是基于实现细节的思考,是当前的实现方式,不是值类型和引用类型的区别。
值类型(struct)更多是性能上的收益,C#中定义的基础值类型已经足够,开发中尽量避免定义值类型(struct)。
期待看到不同的观点和理由!
C# 堆VS栈 值类型VS引用类型的更多相关文章
- C# 托管与非托管类型 堆和栈 值类型与引用类型 装箱与拆箱
一.托管类型与非托管类型 1.托管类型 托管类型包括 引用类型 以及 包含有引用类型或托管类型成员的结构. 引用类型 含引用类型或托管类型成员(字段.自动实现 get 访问器的属性)的结构 // 托管 ...
- C#【堆与栈 值类型 引用类型】
先说C#中值类型和引用类型 概念: 1.值类型:数据存储在内存的堆栈中,从堆栈中可以快速地访问这些数据,因此,值类型表示实际的数据. 2.引用类型:表示指向存储在内存堆中的数据的指针或引用(包括类.接 ...
- 【译】.NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱
为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...
- .NET中的六个重要概念:栈、堆、值类型、引用类型、装箱和拆箱
为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...
- [转] .NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱
为何要转载 一来是最近面试了几家公司,发现问的还都是这些的基础知识,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果. 为什么有人说,不动笔不读书.我现在也是深有体会了,看过的东西不一定会记得 ...
- C#基础知识系列二(值类型和引用类型、可空类型、堆和栈、装箱和拆箱)
前言 之前对几个没什么理解,只是简单的用过可空类型,也是知道怎么用,至于为什么,还真不太清楚,通过整理本文章学到了很多知识,也许对于以后的各种代码优化都有好处. 本文的重点就是:值类型直接存储其值,引 ...
- C# 值类型和引用类型
一.基本概念 C#只有两种数据类型:值类型和引用类型 值类型在线程栈分配空间,引用类型在托管堆分配空间 值类型转为引用类型称成为装箱,引用类型转为值类型称为拆箱 以下是值类型和引用类型对照表 从上图可 ...
- 图解C#的值类型,引用类型,栈,堆,ref,out
C# 的类型系统可分为两种类型,一是值类型,一是引用类型,这个每个C#程序员都了解.还有托管堆,栈,ref,out等等概念也是每个C#程序员都会接触到的概念,也是C#程序员面试经常考到的知识,随便搜搜 ...
- .NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱 (转)
作者: Edison Chou 来源: 博客园 发布时间: 2014-09-03 15:59 阅读: 318 次 推荐: 2 原文链接 [收藏] 原文作者:Shivprasad k ...
随机推荐
- Uva -1515 Pool construction(最小割)
输入一个字符矩阵,'.'代表洞,'#'代表草地.可以把草改成洞花费为d,或者把洞改成草花费为f,最后还要在草和洞之间修围栏花费为b. 首先把最外一圈的洞变成草,并累加花费. 增加一个源点和一个汇点,源 ...
- 动态演示冒泡排序java
动态演示冒泡排序java //冒泡排序是一种简单的交换排序,基本思路,从数列左边开始扫描元素,在扫描过程中依次对相邻元素进行比较,将较大元素后移. public class NumberSort { ...
- 使用百度网盘实现自动备份VPS
http://ju.outofmemory.cn/entry/51536 经过轰轰烈烈的一轮网盘大战,百度网盘的容量已经接近无限(比如我的是3000多G ),而且百度网盘已经开放API,所以用来备份V ...
- 条款十五: 让operator=返回*this的引用
c++程序员经常犯的一个错误是让operator=返回void,这好象没什么不合理的,但它妨碍了连续(链式)赋值操作,所以不要这样做. 一般情况下几乎总要遵循operator=输入和返回的都是类对象的 ...
- hadoop 文件操作
Create a directory in HDFS - mkdir The hadoop mkdir command is for creating directories in the hdfs. ...
- 公用表表达式(CTE)
公用表表达式(CTE,Common table expression)是和派生表很相似的另一种形式的表表达式,而且具有一些重要优势.CTE 是在 SQL Server 2005 中引入的,是ANSI ...
- 用递归将嵌套的JSON对象遍历出来,转为二维数组
如题所示,代码如下: var arJsonNesting = [{id:1,name:"zhang3" ,children:[{id:2,name:"zhang33&qu ...
- 【hdu3544】 Alice's Game
给一块n*m的巧克力,Alice只能垂直切,切成A*m和B*m,并且A+B=n,Bob只能横切,只能切成A*n和B*n,并且A+B=m. 对于n*n的这种巧克力,谁先切了第一刀,就直接让对方有切两刀的 ...
- 【bzoj1029】[JSOI2007]建筑抢修
按照t2从小到大排列之后贪心. 若当前任务可以插入,则插入. 若当前任务不可以插入,分两种情况: ①当前任务的耗时大于等于之前插入的任务的最大耗时:跳过当前任务 ②当前任务的耗时小于之前插入的任务的耗 ...
- C++中UINT32和INT32以及int,BOOL和bool的差别
在AndroidHAL层开发中,编写C++代码的时候.遇到了数据类型的困扰.经过查找资料,总结例如以下: 1.UNIT32和int以及INT32的差别: (1).int默认是signed int.也就 ...