zoukankan      html  css  js  c++  java
  • [转]C#基元类型、引用类型和值类型以及装箱拆箱

    基元类型(primitive type)
    ----------------------------------

    编译器直接支持的类型。

    sbyte / byte / short / ushort / int / uint / long / ulong

    char / float / double / bool / decimal /object / string


    值类型(value type)
    ------------------------------
    值类型实例分配在堆栈(stack)上,值类型变量本身即包含实例所有字段,值类型不受垃圾回收器控制,在离开作用域后自动释放所占内存。所有值类型都继承自ValueType。值类型缺省状态下(未装箱)按值复制方式传递。

    sbyte / byte / short / ushort / int / uint / long / ulong / char / float / double / bool / decimal / 枚举(enum) / 结构(struct)


    引用类型(reference type)
    ------------------------------------
    引用类型都全部或间接继承自Object,引用对象内存必须在托管堆(heap)中分配,引用类型变量包含对象在托管堆中的内存地址。每个引用类型对象实例都包含一些额外附加成员,且需要垃圾回收器回收才能释放内存。注意,引用本身在堆栈中分配。引用类型对象传递时只是复制引用(内存地址)。

    引用对象(Object) / 数组(String) / 数组(Array) / 装箱后的值类型

      

    引用类型和值类型区别

    ------------

      结构体直接继承自System.ValueType;而枚举直接继承自System.Enum, Enum类又直接继承自System.ValueType。

      下面通过例子看一下他们的区别:

      首先定义类和结构体:  

     class SomeRef { public Int32 x; } 
     struct SomeVal { public Int32 x; } 
     1 SomeRef r1 = new SomeRef(); // 分配到堆 
     2 SomeVal v1 = new SomeVal(); // 分配到栈 
     3 r1.x =5; // 所引用的堆空间内数据修改 
     4 v1.x =5; // 直接在栈上复赋值 
     5 Console.WriteLine(r1.x); // "5" 
     6 Console.WriteLine(v1.x); // "5" 
     7 SomeRef r2 = r1; //只把指针复制给了r2 
     8 SomeVal v2 = v1; // 在栈上分配空间,并且将变量内容进行复制 
     9 r1.x = 8; // r1指向(也是r2指向)的内容修改 
    10 v1.x = 9; // 只修改v1内容,v2内容不会受影响 
    11 Console.WriteLine(r1.x); // "8" 
    12 Console.WriteLine(r2.x); // "8" 
    13 Console.WriteLine(v1.x); // "9" 
    14 Console.WriteLine(v2.x); // "5" 

      看看下图的内存分配情况,就一目了然了。

    装箱
    -------------

    装箱:将值类型转换为引用类型。当我们把值类型参数传递给需要引用类型参数的方法时,会自动进行装箱操作。

    步骤:
    1. 从托管堆分配内存,包括添加方法表指针和SyncBlockIndex。
    2. 将值类型字段拷贝到该内存。
    3. 返回该地址的引用。


    拆箱
    ------------

    拆箱:获取指向对象中包含的值类型部分的指针。一般拆箱之后会进行字段拷贝操作,两个操作加起来才是真正与装箱互反的操作。

    步骤:
    1. 如果引用为null,抛出NullReferenceException。
    2. 如果目标不是已装箱的值类型,抛出InvalidCastException。
    3. 返回指向包含在已装箱对象中值类型部分的引用,而不是重新在堆栈建立值类型实例,因此需要GC回收才能释放。


    栈(stack)
    ------------
    位于常规内存区(general random-access memory),处理器可以通过栈指针(stack pointer)对它进行直接访问。指针向下移动创建新的存储空间,向上释放存储空间。是仅次于寄存器(registers)的最快、最有效率的分配内存方法。一般用来存储那些已知大小的值类型和引用,栈中分配的数据在超出作用域后自动被释放。


    堆(heap)
    ------------
    这是一段多用途内存池(general-purpose pool of memory)。堆的优点是分配内存时编译器无需知道该分配多少空间,以及数据的生存期。在堆中分配的对象必须通过垃圾回收期回收后才能释放,因此效率要比栈低一些。

    作者:SamWang
    出处:http://wangshenhe.cnblogs.com/
    本文版权归作者和博客园共有,欢迎围观转载。转载时请您务必在文章明显位置给出原文链接,谢谢您的合作。

  • 相关阅读:
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车按键启动和蜂鸣器报警
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    asp中设置session过期时间方法总结
    asp中设置session过期时间方法总结
    ASP.NET关于Session_End触发与否的问题
  • 原文地址:https://www.cnblogs.com/wangshenhe/p/2511585.html
Copyright © 2011-2022 走看看