首先,要深入.NET Framework就不得不清楚其运行机理,看.NET代码运行最好的地方,莫过于Framework的托管内存变化了.
托管内存不是真实的物理内存,是Framework从物理内存上申请到的内存.物理上讲,申请到的内存就像广场一样,任何代码数据都可以往上放,并没有区别哪个地方一定存放什么类型的数据.但从逻辑功能上讲,Framework托管内存可以分为两大类:代码区和数据区.在数据区中又划分为:堆(heap)和栈(stack).
(一碗八宝粥和内存相似,粥里面有银耳,绿豆,莲子什么的就像代码区和数据区一样.他们不同的作料有不同的作用,但是不固定地方,基本没有可能出现一碗底部全部是莲子,上面全部是绿豆的粥)
代码区(特别的:静态字段,函数统统在代码区,代码区的所有数据不可复制,仅存一份.)
数据区保存各种我们.NET程序运行时要用到的数据的位置.
1int x;
2x=5;
2x=5;
第一句int x执行的时候,其中int 存入代码区.并向栈中申请一段4个字节大小的空间(为什么是4?因为X的类型是INT,所以申请的内存占4个字节).,此时申请到的空间有名称为x但没有内容.同时地址为10936.
第二句x=5执行的时候,表示在栈中申请到的空间内加入5这个值.见下图.如果现在再加一句x=13;则5被覆盖成13.
下面图示(从概念上划分):
其中10936表示数据在栈中的地址,对程序实际执行没有影响.整个内存占4个字节.堆里面是空的.
1string str;
2str=abc;
第一句string str执行的时候,其中string存入代码区.并向栈中申请一段空间.,此时申请到的空间有名称为str但没有内容.同时地址为10933.2str=abc;
第二句str=abc执行时候,在堆中整出块内存(地址为35119)把abc存入,并把内存地址35119付给str在栈中的引用.注意在堆中申请的内存没有名称.
如果再加一句str=xyz的时候,那么在堆中整出块内存(地址为13145)把xyz存入,并把内存地址13145付给str在栈中的引用.那么现在操作str就等于操作xyz.
那么现在abc怎么办?CRL的垃圾自动回收会扫到abc,了解到abc的地址没有被任何变量所引用,则自动删除回收.
在数据区当中,堆和栈分享不同的地址.栈可以直接访问,具有访问速度快的特点.堆不可直接访问,但具有容量大的特点.物理上,一根2G的内存,其栈的容量往往不到5M.现在定义的string类型中,str的容量不一定,可以无限的扩大,所以不可能把string类型的数据放到栈中.而上面的int是固定大小的,所以可以放在栈中.现在要访问abc,则先要访问35119(首地址),通过35119来访问推里面的数据.
需要强调一点是,值类型并不一定只存在栈中,比如在堆里有一块内存,地址为98168,可以在堆里起个名字叫A,值为10,那么相当于变量生成在堆里面了,这样也是值类型.任何时候这样来区分:值类型就是变量和数据存储在一起的.而引用类型则变量中存储的是数据的引用地址.
值类型的数据存储有限,一般包括:整型,浮点,字节,长整,短整,双精,结构,枚举都是值类型.大小固定!
引用类型的数据可以无限扩充的,包括:字符串,数组,类等,以上不可限定大小的一般做引用类型!
那么在内存中存储的这些数据从哪里来的?比如上面的内存10933中存储的str等等是那里来的?是不是我们输入的时候取我们的输入内容放进内存的呢?不是,而是涉及到一个字符串池的东西.