最近博客园上连续出现了几篇关于堆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)

期待看到不同的观点和理由!

最新文章

  1. 解决跑twoBitToFa时出现“/admin/exe/linux.x86_64/twoBitToFa: Permission denied”的问题
  2. react4 props 解析
  3. c++实现des算法
  4. jpush极光推送知识点总结
  5. linux环境(CentOS-6.7)下redis集群的搭建全过程
  6. IOS下移除按钮原生样式 -webkit-appearance
  7. CSS3 column-rule-style 属性
  8. Linux下Nginx的安装与配置
  9. iis 重启 (三种方法)
  10. Codeforces Round #325 (Div. 2) A. Alena's Schedule 水题
  11. IOS7 自定义UIBarButtonItem 的一些问题
  12. MyBatis 学习总结(二)
  13. library cahce pin
  14. Makefiles 介绍
  15. 第四章:Django 的模板系统(转)
  16. sql server 2008 把远程的数据库的数据转移到本地数据数据库里
  17. 独立开发一个云(PaaS)的核心要素, Go, Go, Go!!!
  18. Python多维数组切片
  19. centos6.5新增加硬盘挂载并实现开机自动挂载
  20. 侯捷STL课程及源码剖析学习2: allocator

热门文章

  1. Ubuntu 16.04出现Can't open /etc/rc.d/init.d/functions的问题解决
  2. apple applessd.sys error
  3. JS原生DOM操作总结
  4. 制作svg动画
  5. Sharpdevelop如何在项目中添加类文件
  6. HDU 4968(杭电多校#9 1009题)Improving the GPA (瞎搞)
  7. linux netlink套接字实现相似ss命令 ,统计套接字以及TCP信息
  8. iOS开发——高级篇——iOS 强制退出程序APP代码
  9. HNOI模拟 Day3.22
  10. [Other]面试复习笔记:线程与进程复习