1.值类型直接存储在堆栈中,而引用类型本身存储在托管堆中,堆栈中只存储了对其地址的引用。
2.堆栈和托管堆的解释:
在程序运行中,可以将堆栈理解为程序本身占用的物理内存,代码是嵌套结构(花括号就表示嵌套结构),因此堆栈也是先进后出的顺序。
那么,在内存足够多的情况下,将所有的东西放在一个堆栈中就足够了。
3.然而,考虑以下一种情况:
在程序中定义了一个类A的成员,其本身包含复杂的结构,因此其本身占用内存地址较多,但是很可能在绝大多数情况下我们用到的只是该成员的很少几个属性——试想一下,如果程序中存在很多这样的成员,并且每次使用这个成员时都直接重复地分配相应的内存,那么这个堆栈的体积就会非常巨大。
那么如何解决呢?
1.用指针,即只在堆栈中分配一次该成员,然后每次引用时都利用指针指向该成员地址,这当然是可行的,C语言就是如此。
2.但是C#不这样,因为在堆栈中使用指针是及其不稳定的,因为堆栈中除了成员还有大量的逻辑,一个搞得不好指针就会破坏逻辑从而使程序崩溃。
3.C#的解决办法就是托管内存,将所有的成员(不包含值类别,因为其本身所占内存相对与内存地址大不了多少)都集合到托管堆上,而逻辑分配到堆栈上,这样,运行逻辑所占内存就能最小化,效率也能最大限度地提升,在编译时,将每个成员名编译为该成员在托管堆上的内存地址,不仅使得指针(即引用)更加安全,也能提升效能。
4.凡是被分配到托管堆上的成员均为引用类型。
5.所有的引用类型成员在托管堆上分配新内存时,都使用new()函数实例化(string)除外。
对于引用类型成员的“=”运算符均为复制托管内存地址,即均为引用而非分配新成员。(string除外)
6.这是因为string的"="运算符方法进行了重载,string的“=”方法等同于new()实例化,是一定会在托管堆上分配新内存的,这是为了在减少堆栈内存占用的同时还能使得其符合值类型的特性,以方便程序书写。