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 ...
随机推荐
- int *ptr=(int *)(&a+1)问题的探讨
从网络上看到这样一道有意思的题目,是关于数组与指针的问题,描述如下: main() { ]={,,,,}; ); printf(),*(ptr-)); } 输出为:2,5 请解释以上代码的输出结果. ...
- URL传递多个参数遇到的bug
bug所在: 通过URL传递多个参数的时候,其一是中文出现乱码,其二是空格被“%20”替代: 原因分析:原理暂时还不清楚,后续再研究下原理,只知道有中文的时候就会出现乱码:%20是url空格的编码: ...
- eclipse常用使用指南
1.eclipse添加new/删除/一个tomcat. 步骤:window->preference->server->runtime environment.remove掉,再重新n ...
- git: 保存帐号信息
One line command: git config credential.helper store
- javascript statically scope
在javascript 里面, 函数中使用的未定义的变量,会默认变为全局的变量. 而通过 var 这个关键字定义的变量,就是局部变量. As far as the output is concerne ...
- 云计算VDI相关职位招聘
中电科华云信息技术有限公司是中国优秀的云计算方案提供商和服务商之中的一个.公司依托中国电子科技集团公司,实施"自主.可信.定制.服务"的差异化发展战略,以实现自主创新的技术研发.自 ...
- redux 简明学习
核心概念 redux专注于状态管理,把所有的状态都存在一个对象中.核心概念包括:store.state.action.reducer [store] store是保存数据的地方,redux提供crea ...
- php 获取今天,本周,本月,三个月内,半年内,今年的开始和结束时间
$now = time(); //今天 $today_audit_num = 0; $today_use_num = 0; $beginTim ...
- 【手势交互】8. Nimble Sense
早在2012.2013年度,手势识别领域就发生了几起重要的行业并购.比方英特尔对Omek的收购,谷歌对Flutter的收购.而苹果公司更是以3.45亿美金得高价收购了之前为微软Kinect提供技术支持 ...
- Spring中定时器实现
在Spring 中使用Quartz,本文介绍Spring3.0以后自主开发的定时任务工具,spring task,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关的包外不需 ...