6个重要的.NET概念: - 堆栈,堆,值类型,引用类型,装箱和拆箱(转)
今天在Code Project上面看到一篇文章《6 important .NET concepts: - Stack, heap, Value types, reference types, boxing and Unboxing》,觉得对初学.NET的朋友很有帮助。随手翻译,如有错误欢迎指正和讨论。
(以下是文章作者 Shivprasad koirala的简介和广告)
Watch my 500 videos on various topics like design patterns,WCF, WWF , WPF, LINQ ,Silverlight,UML, Sharepoint ,Azure,VSTS and lot more click here , you can also catch me on my trainings @ click here.
简介:
本文将介绍6个重要的概念,分别是堆栈,堆,值类型,引用类型,装箱和拆箱。首先会简单的解释一下当声明了一个变量的时候,程序的背后会发生什么;之后会介绍堆栈(Stack)和堆(Heap)的概念,然后围绕值类型(Value Type)和引用类型(Reference Type)进行一些探讨。
文章的最后一部分通过一个例子来说明装箱(Boxing)和拆箱(Unboxing)对程序性能方面的影响。

(图片引用自http://michaelbungartz.wordpress.com/)
声明变量时发生了什么?
当你在.NET程序中声明了一个变量的时候,它将会为你在内存中申请一段存储空间,这部分存储包括3个部分: 1.变量名称 2. 变量的类型 3.变量的值
对于不同数据类型,.NET中的变量可能会被分配在堆栈或堆之上,下面我们将会详细的讨论这两种不同的存储类型。

堆栈和堆
我们来分析下面的代码:

;
//Line 3
class1 cls1 = new class1();
}

Line1: 当执行这一段代码的时候,编译器将会在被称作"堆栈"的存储空间中分配一部分内存用于存储变量i。栈同时将会负责监控这部分内存的使用情况。
Line2:程序继续执行到这部分代码。正如"栈"的名称所表示的那样,程序将在刚才分配的空间的“栈顶”上再分配一部分内存用于存储变量j。
可以假想“堆栈”就是许多的的箱子,这些箱子一个接一个的叠放成一摞。
堆栈上存储空间的分配和释放遵循先进后出(LIFO)的原则,也就是说存储空间的分配和释放操作只能在堆栈的一端进行。(其实就是只能在栈顶进行)
Line3:我们在第三行创建了一个对象(Object)。当执行到这段代码的时候,编译器将在堆栈上创建一个指针,而实际的对象将被存储在被称为“堆”的存储空间。“堆”不像“堆栈”那样监控内存的使用情况,它仅仅是将其中的对象排列起来,这部分内存在任何情况下都可以被程序访问。堆用于动态的内存分配。
这里需要指出的一点是:cls1是被分配在堆栈上的。如果仅仅是声明一个对象,例如
{
对于Class1 cls1; 堆上并没有创建任何的存储空间用于存储Class1的对象,它仅在堆栈上创建以一个变量cls1(指向为空)。当执行到new关键字的时候,程序才会在堆上分配相应的内存。
退出方法时:当程序执行到方法的结尾时,将会释放掉该方法在堆栈上分配的空间。换句话说,int类型的变量将按照先进后出的原则被释放出堆栈空间。
这时堆上分配的内存并没有得到释放,这部分内存将会在之后被垃圾收集器收集并最终释放。

有人可能会有疑问,为什么要有两种存储空间类型,难道不能将所有的变量都分配到同一类型中去么?
仔细研究后你会发现,原生数据类型(primitive data type)往往比较简单,他们所包含的数据也很单一,比如“int i = 0”。 而对象数据类型(object data type)往往比较复杂,在对象数据类型中可能会包含其他的对象数据类型和原生数据类型。也就是说对象数据类型中含有多个“内容”而且这些“内容”都必须被存储在内存中。所以对象数据类型需要动态存储空间,而原生数据类型需要静态存储空间。动态存储空间将被分配在堆上而静态存储空间则分配在堆栈上。

值类型和引用类型
当简单了解了堆栈和栈之后,我们来看看值类型和引用类型的概念。
值类型将其所包含的值和其所在的地址存储在一起,而引用类型只包含一个指向其存储地址的指针。
下面的例子中我们将整形变量i的值赋给另一个整形变量j,i和j都的值将被分配到堆栈上。
当我们将一个int变量值赋给另一个int变量时,将会创建一个完全不同的拷贝。也就是说当其中一个值发生变化后,另一个值并不会受到影响。这种数据类型被称作是“值类型”。

当我们创建了一个对象并将该对象赋值给其他对象时,两者都将指向同一内存地址。如下图所示,obj和obj1指向堆上的同一地址。
在这种情况下,当其中一个对象的值被修改之后,另一个对象也会受到影响。我们称这种类型为“引用类型”。

我们有哪些值类型和引用类型?
在.NET中,变量被分配在堆栈上或是分配在堆上是由变量的类型决定的。 “String”和“Objects”是引用类型,而其他的原生类型则将被分配在堆栈上(值类型)。如图所示:

装箱与拆箱
好了,我们已经了解了这么多的相关的知识,那么它们在实际的编程当中有什么用呢?我们可以用它们来帮助理解数据在堆栈和堆之间的转移所带来的性能方面的影响。
来看看下图中的例子。当我们将值类型转换为引用类型时,数据从堆栈上转移到堆上。反过来,将引用类型转换为值类型时,数据从堆转移至堆栈。这种从堆和堆栈的数据转移,将对程序的性能产生不利的影响。
值类型转换为引用类型,我们称之为“装箱”(Boxing),反之,称之为“拆箱”(Unboxing)。

用ILDASM 反编译上面的代码,可以通过中间代码(IL)了解到装箱和拆箱操作,如下图所示:

装箱和拆箱的对程序造成的性能影响
我们可以分别执行下列的两个方法各10000次,第一个方法包含装箱的操作,而另一个比较简单。
含有装箱操作的方法需要执行3542毫秒,而另一方法执行了2477毫秒,所以,在实际应用当中,应该尽量避免出现装箱和拆箱的操作,仅在必需的情况下,再去使用它们。

源代码
本文中出现的装箱和拆箱操作所造成的性能影响的对比示例。
2011/4/14修改:大家看完本文后如果想更深入的了解.NET中堆和栈的关系,推荐这篇文章http://www.cnblogs.com/c2303191/articles/1065675.html
6个重要的.NET概念: - 堆栈,堆,值类型,引用类型,装箱和拆箱(转)的更多相关文章
- 6个重要的.NET概念:栈,堆,值类型,引用类型,装箱,拆箱
引言 本篇文章主要介绍.NET中6个重要的概念:栈,堆,值类型,引用类型,装箱,拆箱.文章开始介绍当你声明一个变量时,编译器内部发生了什么,然后介绍两个重要的概念:栈和堆:最后介绍值类型和引用类型,并 ...
- [No0000136]6个重要的.NET概念:栈,堆,值类型,引用类型,装箱,拆箱
引言 本篇文章主要介绍.NET中6个重要的概念:栈,堆,值类型,引用类型,装箱,拆箱.文章开始介绍当你声明一个变量时,编译器内部发生了什么,然后介绍两个重要的概念:栈和堆:最后介绍值类型和引用类型,并 ...
- C# 托管与非托管类型 堆和栈 值类型与引用类型 装箱与拆箱
一.托管类型与非托管类型 1.托管类型 托管类型包括 引用类型 以及 包含有引用类型或托管类型成员的结构. 引用类型 含引用类型或托管类型成员(字段.自动实现 get 访问器的属性)的结构 // 托管 ...
- C#基础知识系列二(值类型和引用类型、可空类型、堆和栈、装箱和拆箱)
前言 之前对几个没什么理解,只是简单的用过可空类型,也是知道怎么用,至于为什么,还真不太清楚,通过整理本文章学到了很多知识,也许对于以后的各种代码优化都有好处. 本文的重点就是:值类型直接存储其值,引 ...
- .NET六大剑客:栈、堆、值类型、引用类型、装箱和拆箱
.NET六大剑客:栈.堆.值类型.引用类型.装箱和拆箱 一.“堆”,“栈”专区 这两个字我相信大家太熟悉了,甚至于米饭是什么?不知道...“堆”,“栈”是什么?哦,这个知道... 之前我也写过一篇堆栈 ...
- 深入C#内存管理来分析值类型&引用类型,装箱&拆箱,堆栈几个概念组合之间的区别
C#初学者经常被问的几道辨析题,值类型与引用类型,装箱与拆箱,堆栈,这几个概念组合之间区别,看完此篇应该可以解惑. 俗话说,用思想编程的是文艺程序猿,用经验编程的是普通程序猿,用复制粘贴编程的是2B程 ...
- 【译】.NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱
为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...
- .NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱 (转)
作者: Edison Chou 来源: 博客园 发布时间: 2014-09-03 15:59 阅读: 318 次 推荐: 2 原文链接 [收藏] 原文作者:Shivprasad k ...
- .NET中的六个重要概念:栈、堆、值类型、引用类型、装箱和拆箱
为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...
随机推荐
- .NET Core版本七牛云SDK使用
一.问题背景 公司目前正在将一部分的业务从.NET平台准备迁移到.NET Core上去,同时也准备启用docker进行.NET Core的部署,在项目迁移过程中,不可避免的碰到有些SDK只有在.NET ...
- 发放春节福利,ASP.NET Core断点续传
ASP.NET Core断点续传 在ASP.NET WebAPi写过完整的断点续传文章,目前我对ASP.NET Core仅止于整体上会用,对于原理还未去深入学习,由于有园友想看断点续传在ASP.NET ...
- linux打印彩色字
echo显示带颜色,需要使用参数-e格式如下:echo -e "\033[字背景颜色;文字颜色m字符串\033[0m"例如: echo -e "\033[41;37m T ...
- IDEA的优质使用博客资源
intelliJ idea 使用技巧&方法 IntelliJ IDEA 常用设置讲解 IntelliJ IDEA 详细图解最常用的配置 ,适合刚刚用的新人. IntelliJ IDEA 常见文 ...
- ps删除或覆盖内容
除了选区删除.复制选区内容覆盖之外另外一种方法. 删掉字母"PS": 1. 矩形框选工具在字母上方画出选区 2. Ctrl+T,并拖拽底部以覆盖字母 3. 完成
- 拥抱.NET Core系列:MemoryCache 初识
Cache是一个绝大多数项目会用到的一个技术,说起到缓存可能就联想到 Set.Add.Get.Remove.Clear 这几个方法.那么在.NET Core中微软给我们带来了什么样的缓存体验呢?今天我 ...
- 阿里云Aliyun_server
一.云概念 云主机是基于云计算平台的一种虚拟的主机服务器产品 云服务器(99.999%安全性,扩展性) 特点: 1.资源分配配置灵活,安全性能强. 2.优于VPS和独立服务器产品.通俗的理解: 云主机 ...
- [翻译]编写高性能 .NET 代码 第一章:性能测试与工具 -- 平均值 vs 百分比
<<返回目录 平均值 vs 百分比 在考虑要性能测试的目标值时,我们需要考虑用什么统计口径.大多数人都会首选平均值,但在大多数情况下,这个正确的,但你也应该适当的考虑百分数.但你有可用性的 ...
- C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward
这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理 ...
- 2018-03-03-解决win下凭据删除不干净而无法登录共项目录的问题
layout: post title: 2018-03-03-解决win下凭据删除不干净而无法登录共项目录的问题 key: 20180303 tags: GIT 版本管理 modify_date: 2 ...