C# 值类型,引用类型

1,值类型
值类型:int,float,char,bool,枚举, struct ,可空类型 
概念:值类型直接存储其值,而引用类型存储对其值的引用。
对于值类型来说,一般创建在线程的堆栈上。引用类型包含值类型时,值类型作为实例成员的一部分被创建在托管堆上。
值类型变量声明后,不管是否已经赋值,编译器为其分配内存。
每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。
int i = new int();等价于:Int32 i = new Int32();等价于:int i = 0;等价于:Int32 i = 0;由C#通用类型系统可知,int就是Int32的一个实例。
装箱发生时,值类型字段会拷贝在托管堆上。
值类型按引用传递时,不会对值类型装箱。

2,引用类型
概念:值类型直接存储其值,而引用类型存储对其值的引用。
引用类型:string,class,数组(派生于System.Array),委托(派生于System.Delegate),接口。
引用类型当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。

3,为什么托管堆更慢?
数据结构中的栈(后进先出的线性表),堆(经过某种排序的二叉树),一种概念。
语言中stack与heap指的是内存中的某一个区域。

如下是托管堆更慢的原因:
cpu有专门的寄存器(esp,ebp)来操作栈,堆都是使用间接寻址的。所以栈更快。存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
栈是编译时分配空间,而堆是动态分配(运行时分配空间),所以栈的速度快。
栈是程序启动的时候,操作系统分好了给你的。堆是用的时候才向系统申请的,用完了还回去,这个申请和交还的过程开销相对就比较大了。

引用类型在性能上欠于值类型的原因:
引用类型变量要分配于托管堆上,内存释放则由GC完成,造成一定的CG堆压力,且必须完成对其附加成员的内存分配过程,以及对象访问问题。

3,数组
数组是引用类型
TestType[] testTypes = new TestType[100];
如果TestType是值类型,则会一次在托管堆上为100个值类型的元素分配存储空间,并自动初始化这100个元素,将这100个元素存储到这块内存里。
如果TestType是引用类型,则会先在托管堆为testTypes分配一次空间,并且这时不会自动初始化任何元素(即testTypes[i]均为null)。等到以后有代码初始化某个元素的时候,会先在托管堆上分配实例对象的地址,然后再在托管堆上创建实例对象。
如下:
public class ReceiveTest : MonoBehaviour
{
    private void Awake()
    {
        int[] iArr = new int[10];
        print(iArr[0]);//打印 0
        TestFruit[] tf = new TestFruit[10];
        print(tf[0]);//打印 null
        tf[0] = new TestFruit();
        print(tf[0]);//打印 TestFruit(类的名字)
        print(tf[1]);//打印 null
        print(tf[0].apple);//打印 0
    }
}
public class TestFruit
{
    public int apple;
}

4,字符串
字符串是引用类型
string s1 = "a"; string s2 = s1; s1 = "b";//s2 is still "a"
改变s1的值对s2没有影响。这更使string看起来像值类型。实际上,这是运算符重载的结果,当s1被改变时,.NET在托管堆上为s1重新分配了内存。这样的目的,是为了将做为引用类型的string实现为通常语义下的字符串。

猜你喜欢

转载自blog.csdn.net/tran119/article/details/81386838