匿名类型&&堆和栈

匿名类型

在前面的代码中,我们创建变量(对象)的时候,都指定了变量的类型,但是我们也可以不去指定类型,这个就叫做匿名类型。

我们可以使用var声明一个匿名类型,匿名类型初始化的时候,这个变量的类型就被确定下来了,并且之后不能够在被修改。

static void Main(string[] args)
        {
            int i = 100;
            var j = 1000;
            j = 98;
            j = "sdwd"; //j的类型已经被确定为int类型,不能够被修改了
            var a = "asdwd";
            var v1 = new Vector3();
        }

在这段代码中我们可以看到j被确定为int类型之后不能够再被定义为string类型了。


堆和栈

堆和栈是程序运行时的内存区域,我们把内存分为堆空间和栈空间。
栈空间:空间较小但是读取速度快,数据只能从栈的顶端插入和删除,把数据放入栈顶称为入栈(push),从栈顶删除数据称为出栈(pop)。
堆空间:空间较大但是读取速度慢。与栈不同,堆空间的内存能够以任意顺序存入和溢出。


讲到程序运行的内存区域,就要谈到内存的回收。C语言里的内存管理可以由自己来完成,但是C#里面内存管理我们可以不用去关心,因为CLR(公共语言运行库)里的内存管理机制会自动帮我们回收无用的内存。(CLR在第一篇文章有大概的描述。)
内存管理机制又被称作GC(垃圾回收器),在堆空间中,一旦有对象不再被程序使用,垃圾回收器发现无主对象,就会释放该对象,释放之后,该对象占据的内存空间就可以重新被使用了。

值类型和引用类型

既然有堆和栈两种内存区域,那我们定义的变量是应该放在哪种区域呢?不同类型存放的区域是不一样的。
值类型:存放在栈空间(包括整数,bool,struct,char,小数这几种类型)。值类型只需要一段单独的内存用于存储实际的数据。
引用类型:存放在堆空间(包括string,数组,自定义的类,内置的类)。
引用类型需要两段内存:第一段存储实际的数据,这段内存总是位于堆中;第二段是一个引用,存放着内存地址,指向数据在堆中的存放位置,该引用位于栈中。

内存分析
当一个方法中同时有值类型和引用类型,在程序结束之后,GC会先释放一个在栈中的内存空间,然后检查堆空间有没有无主对象,有的话就释放该对象占据的空间,没有的话就释放栈的内存空间,循环往复。


当一个引用类型赋值给另一个引用类型的时候,并不是修改堆空间内的数值,而是修改栈空间的里的内存地址。

static void Test3()
        {
            string name = "lymon";
            string name2 = "baidu";
            name = name2;
            Console.WriteLine(name + name2);
        }

在这段代码中,name2赋值给name,实质上,name指向的是“lymon”这段数据,当赋值之后,name就指向了“baidu”这段数据,而“lymon”这段数据没有被修改,只是没有被栈空间里的数据引用了。


和上面的情况一样,一个引用类型赋值给另一个引用类型,那么当内村回收之后,堆空间只剩下一块内存空间,被赋值的引用类型的堆内存消失,这时候两个引用类型都指向同一段数据,无论怎么修改,都是修改同一块内存空间。

static void Test4()
        {
            Vector3 v = new Vector3();
            v.x = 100;
            v.y = 100;
            v.z = 100;
            Vector3 v2 = new Vector3();
            v2.x = 200;
            v2.y = 200;
            v2.z = 200;
            v2 = v;
            v2.x = 300;
            Console.WriteLine(v.x);
        }

Vector3是只定义了x,y,z的类。当v赋值给v2时,v2指向的堆内存的数据就消失了,这时v和v2指向的都是v的数据,所以当v2.x=300的时候,v.x的值也为300。


还有一种更复杂的情况,就是引用类型的嵌套。
例如在数组中,存储的是值类型的数据,那么在数组中直接存储值;但是数组里要是存储的是引用类型的数据,那么数组中存储的就是内存地址了,然后内存地址再去指向数值。

static void Test5()
        {
            Vector3[] vArray = new Vector3[] { new Vector3(), new Vector3(), new Vector3() };
            Vector3 v1 = vArray[0];
            vArray[0].x = 100;
            v1.x = 200;
            Console.WriteLine(vArray[0].x);
        }

在这个例子中,vArray数组中存的是三个引用类型,vArray在栈中存储了一个内存地址,指向堆空间的一段数据,该数据又存储了三个内存地址,分别指向xyz数值。
这里写图片描述
整个程序的内存关系大概就是这个样子。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值