• C# 托管与非托管类型 堆和栈 值类型与引用类型 装箱与拆箱


    一.托管类型与非托管类型

    1.托管类型

    托管类型包括 引用类型 以及 包含有引用类型或托管类型成员的结构。

    • 引用类型
    • 含引用类型或托管类型成员(字段、自动实现 get 访问器的属性)的结构
    // 托管结构。 (这里的struct 包含了引用类型字段)
    public struct Foo { 
          public string Name; // 包含引用类型字段。
          public string Bar { get; private set; } // 包含自动实现 get 访问器的引用类型属性。
     }
     
     public struct Bar { 
          public Foo Foo; // 包含托管类型字段(托管结构)。
    }

    托管需要由GC自动释放

    2.非托管类型

    如果某个类型是以下类型之一,则它是非托管类型 :

    • sbytebyteshortushortintuintlongulongcharfloatdoubledecimal 或 bool
    • 任何枚举类型
    • 任何指针类型
    • 任何用户定义的 struct 类型,只包含非托管类型的字段

    非托管需要自己手动释放  可以继承IDispose  using等

    二.堆和栈

    堆和栈:程序运行时的内存区域

    我们把内存分为堆空间和栈空间。

          栈空间比较小,但是读取速度快

          堆空间比较大,但是读取速度慢

    1.堆(先进后出)

    栈的特征:

         数据只能从栈的顶端插入和删除

         把数据放入栈顶称为入栈(push)

         从栈顶删除数据称为出栈(pop)

     2.堆

    堆是一块内存区域,与栈不同,堆里的内存能够以任意顺序存入和移除

     三.值类型和引用类型

    栈比堆快 值类型快,值类型和引用类型变量本身在栈中分配内存,引用类型的实例在堆中分配内存

     类型被分为两种:值类型(结构类型,枚举类型,byte,short,int,long,float,double,decimal,char,bool 和 struct )和引用类型(string ,object,接口,类,字符串,数组,委托)。

      1)值类型只需要一段单独的内存,用于存储实际的数据,(如果值类型是在方法内部创建,则跟随方法入栈,分配到栈上存储。如果值类型是引用类型的成员变量,则跟随引用类型,存储在堆上。

      2)引用类型需要两段内存 (一块空间分配在堆上,存储引用类型本身的数据,另一个块空间分配在栈上,存储对堆上数据的引用(实际上存储的堆上的内存地址,也就是指针)。)

     注意: 但我们使用引用类型赋值时,其实是赋值的引用类型的引用,如果数组是一个值类型的数组,那么数组中直接存储值,如果是一个引用类型的数组(数组中存储的是引用类型),那么数组中存储的是引用(内存地址)。

    • 值类型变量声明后,不管是否已经赋值,编译器为其分配内存。
    • 引用类型当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。
    • 值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。
    • 引用类型的对象总是在进程堆中分配(动态分配)

    相同点:

    引用类型可以实现接口,值类型当中的结构体也可以实现接口;引用类型和值类型都继承自System.Object类。

    不同点:

    几乎所有的引用类型都直接从System.Object继承,而值类型则继承其子类,即 直接继承System.ValueType。即System.ValueType本身是一个类类型,而不是值类型。其关键在于ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。

    四.装箱拆箱

    值类型→引用类型(装箱),引用类型→值类型(拆箱)

    //装箱 boxing
    int i = 3 ;  //分配在栈上
    object o = i ;//隐式装箱操作,int i 在堆上
    object b = (object)i ; //显示装箱操作
    //拆箱 unboxing
    int j = (int) o ;//显示拆箱(将对象o拆箱为int类型)
     
    int k = b ;//error!!, 不能隐式拆箱

    下面来看看这个例子:

    int i=0;
    System.Object obj=i;
    Console.WriteLine(i+","+(int)obj);

    其中共发生了3次装箱和一次拆箱!^_^,看出来了吧?!
    第一次是将i装箱,第2次是输出的时候将i转换成string类型,而string类型为引用类型,即又是装箱,第三次装箱就是(int)obj的转换成string类型,装箱!
    拆箱就是(int)obj,将obj拆箱!!

  • 相关阅读:
    3.25Java常量
    3.26Java逻辑运算符
    3.26Java关系运算符
    Java标识符
    3.27Java位运算符
    3.26Java运算符(operator)
    3.26Java字符型(char)变量、常量
    3.26Java布尔类型(boolean)变量、常量
    《算法导论》第9章 顺序统计学 (1)最小值和最大值
    《算法导论》第8章 线性时间排序 (1)计数排序
  • 原文地址:https://www.cnblogs.com/netlock/p/13731422.html
Copyright © 2020-2023  润新知