第八回:品味类型---值类型与引用类型(上)-内存有理

http://www.cnblogs.com/anytao/archive/2007/05/23/must_net_08.html

发布日期:2007.5.23 作者:Anytao

©2007 Anytao.com ,原创作品,转贴请注明作者和出处。

本文将介绍以下内容:

  • 类型的基本概念
  • 值类型深入
  • 引用类型深入
  • 值类型与引用类型的比较及应用

1. 引言

买了新本本,忙了好几天系统,终于开始了对值类型和引用类型做个全面的讲述了,本系列开篇之时就是因为想写这个主题,才有了写个系列的想法。所以对值类型和引用类型的分析,是我最想成文的一篇,其原因是过去的学习过程中我就是从这个主题开始,喜欢以IL语言来分析执行,也喜好从底层的过程来深入了解。这对我来说,似乎是一件找到了有效提高的方法,所以想写的冲动就没有停过,旨在以有效的方式来分享所得。同时,我也认为,对值类型和引用类型的把握,是理解语言基础环节的关键主题,有必要花力气来了解和深入。

2. 一切从内存开始

2.1 基本概念

从上回《第七回:品味类型---从通用类型系统开始》我们知道,CLR支持两种基本类型:值类型和引用类型。因此,还是把MSDN这张经典视图拿出来做个铺垫。

值类型(Value Type),值类型实例通常分配在线程的堆栈(stack)上,并且不包含任何指向实例数据的指针,因为变量本身就包含了其实例数据。其在MSDN的定义为值类型直接包含它们的数据,值类型的实例要么在堆栈上,要么内联在结构中。我们由上图可知,值类型主要包括简单类型、结构体类型和枚举类型等。通常声明为以下类型:int、char、float、long、bool、double、struct、enum、short、byte、decimal、sbyte、uint、ulong、ushort等时,该变量即为值类型。

引用类型(Reference Type),引用类型实例分配在托管堆(managed heap)上,变量保存了实例数据的内存引用。其在MSDN中的定义为引用类型存储对值的内存地址的引用,位于堆上。我们由上图可知,引用类型可以是自描述类型、指针类型或接口类型。而自描述类型进一步细分成数组和类类型。类类型是则可以是用户定义的类、装箱的值类型和委托。通常声明为以下类型:class、interface、delegate、object、string以及其他的自定义引用类型时,该变量即为引用类型。

下面简单的列出我们类型的进一步细分,数据来自MSDN,为的是给我们的概念中有清晰的类型概念,这是最基础也是最必须的内容。

2.2 内存深入

2.2.1. 内存机制

那么.NET的内存分配机制如何呢?

数据在内存中的分配位置,取决于该变量的数据类型。由上可知,值类型通常分配在线程的堆栈上,而引用类型通常分配在托管堆上,由GC来控制其回收。例如,现在有MyStruct和MyClass分别代表一个结构体和一个类,如下:

using System;

public class Test
{
    static void Main()
    {
        //定义值类型和引用类型,并完成初始化
        MyStruct myStruct = new MyStruct();
        MyClass myClass = new MyClass();
        
        //定义另一个值类型和引用类型,
        //以便了解其内存区别
        MyStruct myStruct2 = new MyStruct();
        myStruct2 = myStruct;
        
        MyClass myClass2 = new MyClass();
        myClass2 = myClass;        
    }
}

在上述的过程中,我们分别定义了值类型变量myStruct和引用类型变量myClass,并使用new操作符完成内存分配和初始化操作,此处new的区别可以详见《第五回:深入浅出关键字---把new说透》  的论述,在此不做进一步描述。而我们在此强调的是myStruct和myClass两个变量在内存分配方面的区别,还是以一个简明的图来展示一下:

我们知道,每个变量或者程序都有其堆栈,不同的变量不能共有同一个堆栈地址,因此myStruct和myStruct2在堆栈中一定占用了不同的堆栈地址,尽管经过了变量的传递,实际的内存还是分配在不同的地址上,如果我们再对myStruct2变量改变时,显然不会影响到myStruct的数据。从图中我们还可以显而易见的看出,myStruct在堆栈中包含其实例数据,而myClass在堆栈中只是保存了其实例数据的引用地址,实际的数据保存在托管堆中。因此,就有可能不同的变量保存了同一地址的数据引用,当数据从一个引用类型变量传递到另一个相同类型的引用类型变量时,传递的是其引用地址而不是实际的数据,因此一个变量的改变会影响另一个变量的值。从上面的分析就可以明白的知道这样一个简单的道理:值类型和引用类型在内存中的分配区别是决定其应用不同的根本原因,由此我们就可以很容易的解释为什么参数传递时,按值传递不会改变形参值,而按址传递会改变行参的值,道理正在于此。

对于内存分配的更详细位置,可以描述如下:

  • 值类型变量做为局部变量时,该实例将被创建在堆栈上;而如果值类型变量作为类型的成员变量时,它将作为类型实例数据的一部分,同该类型的其他字段都保存在托管堆上,这点我们将在接下来的嵌套结构部分来详细说明。
  • 引用类型变量数据保存在托管堆上,但是根据实例的大小有所区别,如下:如果实例的大小小于85000Byte时,则该实例将创建在GC堆上;而当实例大小大于等于85000byte时,则该实例创建在LOH(Large Object Heap)堆上。

更详细的分析,我推荐《类型实例的创建位置、托管对象在托管堆上的结构》。

2.2.2. 嵌套结构

嵌套结构就是在值类型中嵌套定义了引用类型,或者在引用类型变量中嵌套定义了值类型,相信园子中关于这一话题的论述和关注都不是很多。因此我们很有必要发挥一下,在此就顺藤摸瓜,从上文对.NET的内存机制着手来理解会水到渠成。

  • 引用类型嵌套值类型

值类型如果嵌套在引用类型时,也就是值类型在内联的结构中时,其内存分配是什么样子呢? 其实很简单,例如类的私有字段如果为值类型,那它作为引用类型实例的一部分,也分配在托管堆上。例如:

public class NestedValueinRef

  //aInt做为引用类型的一部分将分配在托管堆上 
  private int aInt;  
  public NestedValueinRef 
  { 
    //aChar则分配在该段代码的线程栈上 
     char achar = 'a'; 
  } 

其内存分配图可以表示为:

  • 值类型嵌套引用类型

引用类型嵌套在值类型时,内存的分配情况为:该引用类型将作为值类型的成员变量,堆栈上将保存该成员的引用,而成员的实际数据还是保存在托管堆中。例如:

public struct NestedRefinValue
{
    public MyClass myClass;
    public NestedRefinValue
    {
        myClass.X = 1;
        myClass.Y = 2;
    }
}

其内存分配图可以表示为:

2.2.3. 一个简单的讨论

通过上面的分析,如果我们现在有如下的执行时:

AType[] myType = new AType[10];

试问:如果AType是值类型,则分配了多少内存;而如果AType是引用类型时,又分配了多少内存?

我们的分析如下:根据CRL的内存机制,我们知道如果ATpye为Int32类型,则表示其元素是值类型,而数组本身为引用类型,myType将保存指向托管堆中的一块大小为4×10byte的内存地址,并且将所有的元素赋值为0;而如果AType为自定义的引用类型,则会只做一次内存分配,在线程的堆栈创建了一个指向托管堆的引用,而所有的元素被设置为null值,表示为空。

未完,下回即将发布。。。

参考文献

(USA)Jeffrey Richter, Applied Microsoft .NET Framework Programming

(USA)David Chappell, Understanding .NET

广而告之

本文有些长,因此分两回来展开。我们已经分析了类型的内存机制,接下来就该着重于类型的实际应用领域了,因此在下回中我们会从[通用规则与区别]、[实例分析]、[应用场合]、[类型比较]等几个方面来着重展开,希望给大家以帮助,对于表达有谬或者理解有误的地方还望不吝赐教,本人将不胜感激。

To be continue soon ...

第八回:品味类型---值类型与引用类型(上)-内存有理相关推荐

  1. [你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理

    本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型与引用类型的比较及应用 1. 引言 买了新本本,忙了好几天系统,终于开始了对值类型和引用类型做个全面的讲述了,本系列开篇之时就是因 ...

  2. 【转】[你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理...

    引用自:http://www.cnblogs.com/anytao/category/155694.html 作者:Anytao 本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型 ...

  3. [你必须知道的.NET]第九回:品味类型---值类型与引用类型(中)-规则无边

    发布日期:2007.5.28 作者:Anytao ©2007 Anytao.com ,原创作品,转贴请注明作者和出处. 接上回[第八回:品味类型---值类型与引用类型(上)-内存有理]的探讨,继续我们 ...

  4. [你必须知道的.NET]第十回:品味类型---值类型与引用类型(下)-应用征途

    本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型与引用类型的比较及应用 [下载]:[类型示例代码] 1. 引言 值类型与引用类型的话题经过了两个回合([第八回:品味类型---值类 ...

  5. [导入][你必须知道的.NET]第十回:品味类型---值类型与引用类型(下)-应用征途...

    摘要: 本文将值类型和引用类型的讨论从应用示例角度来进一步做以延伸,可以看作是对前两回的补充性探讨.我们从类型定义.实例创建.参数传递.类型判等.垃圾回收等几个方面来简要的对上两回的内容做以剖析,并以 ...

  6. 一起Talk IOS吧(第八回 OC中复合类型的代码演示)

    看官们,我们在第三回中介绍了OC中的复合类型,有看官说介绍的不够详细,因此我使用图形的方式对所有基本类型做了总结,请参考以下图片中的内容. 看完类型的总结后,我们将通过具体的代码来演示如何使用这些类型 ...

  7. 值类型与引用类型(下)

    本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型与引用类型的比较及应用 [下载]:[类型示例代码] 1. 引言 值类型与引用类型的话题经过了两个回合([第八回:品味类型---值类 ...

  8. 值类型和引用类型的区别

    一.定义 引用类型表示你操作的数据是同一个,也就是说当你传一个参数给另一个方法时,你在另一个方法中改变这个变量的值,那么调用这个方法是传入的变量的值也将改变. 值类型表示复制一个当前变量传给方法,当你 ...

  9. CLR via C#-基元类型、引用类型和值类型

    理解不同的类型之间的区别,可以提高编码效率. 基元类型(primitive type) 编辑器直接支持的数据成为基元类型 int => System.Int32 sbyte.byte.short ...

最新文章

  1. Easyui textbox 组件设置css样式
  2. stdafx.h头文件
  3. 软考高项之各大管理计划内容-攻坚记忆
  4. 数据中心夏季如何防雷
  5. 打造数字化服务能力,中国联通如何借助云原生技术实现增长突围?
  6. 适用于 deno 的多版本管理工具 dvm 发布
  7. Git Bash推送GitHub不成功---密钥设置
  8. 手机拨不了急救电话 延误就医?魅族回应:仅是个例
  9. element icon图标方向旋转
  10. RTOS原理与实现06:计数信号量实现
  11. fpga一个按键控制跑马灯启停_车上这些开关都认识吗?一次带你认清车上按键...
  12. php客户订单管理系统,PHP订单管理系统完整版源码PHP订单管理系统完整版源码
  13. 超大流量分布式系统架构解决方案 人人都是架构师2.0
  14. [整理]ISO 27001信息安全管理体系审核员试题汇编之单项选择题
  15. TQ2440开发板移植UBOOT-2010.06总结(2)
  16. 水滴动态IP:自动换IP软件哪个好用?换IP的原理是什
  17. asyncio 系列五、asyncio的事件循环
  18. 差之毫厘:etcd 3 完美支持 HTTP 访问
  19. windows驱动快速入门
  20. 【推荐+转摘】如何又快又好的做出一份优质PPT

热门文章

  1. 【LeetCode每周算法】零钱兑换
  2. 在cmd中使用指令来执行jar包
  3. Fedora17 开启ssh服务
  4. eclipse3.6默认指向 WebContent 目录 修改为 webRoot
  5. 四级计算机网络考试大纲,2017年全国计算机等级考试四级计算机网络考试大纲...
  6. 阿里云云原生应用平台总经理丁宇:“连接、合作、赋能”,携手加速器伙伴助力企业云上创新
  7. 深度解读 OpenYurt :边缘自治能力设计解析
  8. IDEA 中 30 秒生成 Spring Cloud Alibaba 工程
  9. Knative 初体验:Build Hello World
  10. java hook 框架_hook框架-frida简单使用模板以及frida相关接口