目录
1 值类型与引用类型
1.1 线程堆栈和托管堆
值类型:int、double、enum、struct
引用类型:类、接口、数组、委托、String
值类型变量与引用型变量的内存分配模型不同。分为“线程堆栈(Thread Stack)”和“托管堆(Managed Heap)”。
每个正在运行的程序都有一个“进程(Process)”,在一个进程内部,可以存在多个“线程(Thread)”,每个线程都拥有一个“线程堆栈”,大小为1MB。
值类型的变量所占用的内存单元是在线程堆栈中分配的。
引用类型变量引用的对象所占用的内存是在托管堆中分配的。
注:在.NET的托管环境下,堆由CLR进行管理,所以将其称为“托管堆”。用new关键字创建对象时,分配给对象的内存单元就位于托管堆中。
1.2 引用类型变量的内存模型
在C#程序中,我们可以使用new关键字创建多个对象,因此托管堆中的内存资源是可以动态申请并使用的,但用完需要释放。
下面通过一个实列来介绍引用类型变量的内存模型:
private void TestFunc()
{
MyClass obj;
obj = new MyClass();
}
创建MyClass对象的代码:
class MyClass
{
public int Value;
public int[] Numbers = new int[10];
}
此时内存对象模型如图所示。
引用类型变量obj “生存” 于线程堆栈中(因为它是TestFunc方法的局部变量),而MyClass对象则生存与托管堆中,obj 所代表的位于线程堆栈中的内存单元保存了托管堆中MyClass对象的首地址。
(注:引用类型对象一般分为两部分:对象引用和对象实列。对象引用存放在栈中,程序使用该引用访问堆中的对象实例;对象实例存放在堆中,里面包含对象的数据内容)
1.3 “=” 和 “==” 辨析
引用类型赋值
MyClass obj1 = new MyClass() { Value = 100 };
MyClass obj2 = null;
obj2 = obj1; // 引用类型变量的赋值
Console.WriteLine("obj2.Value = " + obj2.Value); // 输出obj2.Value = 100;
整个过程可以用下图来说明:
两个引用类型变量的相互赋值不会导致它们所引用的对象自身被复制,其结果是这两个引用类型的变量引用同一对象。