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技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...
随机推荐
- jquery对象和DOM对象的区别和转换
jquery对象和DOM对象的区别和转换 在使用jquery时,我们直接通过jq的选择器获取元素,然后对元素进行操作,用jq选择器获取到的对象是一个jq对象,jq对象能够使用jq提供的方法,但是不能用 ...
- 如何用vue-cli初始化一个vue项目
单文件组件和vue-loader 解析打包.vue文件 vue为了能够使我们在项目开发中对组件进行更好的维护,提供了一个单文件组件系统,vue把每一个独立的组件放在一个.vue的文件中,在这个文件中提 ...
- [Python Study Notes] 编程仪式感的Hello World!
学习还是要有一点仪式感的,学单片机第一步,点个灯:学编程第一步,hello world! C:\Users\Liu>python Python 3.6.4 (v3.6.4:d48eceb, De ...
- golang验证提交的数据中某个字段是否重复
提交的json数据如下: { , , , ", , , "screen_mode": "3,2", , "ad_plats":[ ...
- Windows 系统下安装 dig 命令
dig是一个Linux下用来DNS查询信息的小工具,dig全称是Domain Information Groper,与nslookup类似,但比nslookup功能更强大.Windows只有nsloo ...
- Filezilla Server 出现Error, could not connect to server解决办法
打开任务管理器:Win+R:services.msc找到Filezilla Server并启动服务
- 如何让div水平居中呢?
一百度div居中,多数都是一个答案,但是有时候这种方法并不是万能的...不废话,将我知道的方法都列举一下好了,随时更新. 1.设置width值,指定margin-left和margin-right为a ...
- es2015及es2017对我们的编程方式造成了什么影响?
记一些写代码中用得到的es6+语法,至于什么正则的拓展,数组的什么fill方法,对我们来说用处不大,就不提及了. 还有es6的import模块和class模块,这些在各种框架中都有体现,而且语法简单, ...
- 《android开发艺术探索》读书笔记(十)--Android的消息机制
接上篇<android开发艺术探索>读书笔记(九)--四大组件 No1: 消息队列MessageQueue的内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息列表,因为单链表 ...
- javascript正则表达式的一些笔记
正则表达式:Regular Expression.使用单个字符串来描述,匹配一系列符合某个句法规则的字符串.即按照某种规则去匹配符合条件的字符串.正则表达式就是规则. \b 单词边界 regexp对象 ...