一:C#语言中的数据类型
C#的数据类型分为两类:值类型(基本的数据类型)和引用类型
值类型:byte、int、float、bool、struct.....
引用类型:string、数组(继承自System.Array)、接口、自定义的类、内置的类.....
二:堆和栈
我们把内存分为堆空间和栈空间
栈空间比较小,但是读取速度快
堆空间比较大,但是读取速度慢
三:GC的简介
CLR中的GC(Garbage Collector 垃圾回收器)就是内存管理机制,C#中不需要我们关心内存的使用,因为CLR帮我们做了
例如在堆中一共有两个对象被引用着,当其中一个对象的引用断开,GC发现没有对象引用着它,那么会在某个时刻自动释放它的内存,释放后这块内存可以被重用
四:值类型和引用类型
——值类型的变量在声明时,不管有没有赋值,编译器都会为其在栈上分配内存。引用类型的变量在声明时只会在栈中分配一小段内存用于容纳一个地址,当使用new创建时才会在堆上开辟一个内存,并把堆上空间的地址保存到栈上分配的小片空间中
——值类型只需要一段单独的内存去存储实际的数据,一般在栈中存储。引用类型需要两段内存,一段存储实际的数据,在堆中存储,另一段是一个内存地址,在栈中存储,指向数据在堆中的内存。为什么说值类型一般在栈中存储而不是一定,因为比如数组的元素,引用类型中的值类型字段,迭代器的局部变量(分配在线程栈上会出现线程栈方法调用结束后却依旧在访问这些值的情况),匿名函数的局部变量会分配在托管堆上(分配在线程栈上会出现线程栈方法调用结束后却依旧在访问这些值的情况)
——值类型和引用类型的基类都是System.Object,值类型继承自System.ValueType,System.ValueType继承自System.Object,ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较
——值类型和引用类型都可以实现接口
——值类型不能被继承,因为都是隐式密封类(一种规范),引用类型可以派生出新的类型
——栈的内存是自动释放的,堆内存是由GC来自动释放
——不要认为值类型的结构体一定比引用类型轻量,比如在作为参数传递时,引用类型只需要传递地址,而结构体需要复制全部的数据
结构体和类的区别
——结构体是值类型,类是引用类型
——结构体中不能定义无参的构造函数,类可以
——结构体中不允许初始化字段,类可以
——结构体定义时,就在栈上分配了内存空间,所以不需要通过new来初始化就可以,而类需要通过new初始化
——结构体不能被继承,类可以
——结构体和类都可以实现接口
什么情况下使用值类型?什么情况下使用引用类型?
——因为结构存储在栈中,栈的空间小访问速度快,所以当存储一些轻量级的值时(int,double.....)比如颜色、点等,使用值类型
——当它不需要作为参数传递时,使用值类型
——当它不会频繁地装箱和拆箱时,使用值类型
五:几种不同情况下的内存存储
——第一种
首先依次将a、b、c依次入栈,因为都是值类型,所以直接保存值,之后name赋值时栈中存的是name的地址,引用堆中的数据“liu”
——第二种(正常的引用类型)
当使用引用类型赋值时,其实赋值的是引用类型的引用(地址),并不是实际值
当str[0]赋值b1时,操作的其实是同一块内存空间,并不是操作的新的内存空间
——第三种(特殊的引用类型,string类型比较特殊)
当使用引用类型赋值时,其实赋值的是引用类型的引用(地址),并不是实际值
当str赋值chen时,是系统在堆中又开辟了一段新的内存空间去存储string类型chen的实际值
——第四种
v1,v2都是自定义类型,为引用类型,当执行v1=v2时,v1与v2的内存地址都引用了同一块堆中的实际内存区域,所以操作v1.x就相当于操作v2.x